From 0be0bfcbd99ab9afe8681888cc8a9c2e1699883a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 30 Aug 2021 17:45:16 -0400 Subject: [PATCH 01/17] Move TyVid to rustc_index --- compiler/rustc_infer/src/infer/fudge.rs | 2 +- .../rustc_infer/src/infer/type_variable.rs | 16 +++++++------- .../src/traits/error_reporting/suggestions.rs | 4 ++-- compiler/rustc_type_ir/src/lib.rs | 21 +++++++------------ .../rustc_typeck/src/check/method/suggest.rs | 2 +- 5 files changed, 20 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index c292b2bdb3040..35ebe92c59246 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.index - self.type_vars.0.start.index) as usize; + let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize; let origin = self.type_vars.1[idx]; self.infcx.next_ty_var(origin) } else { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index d2b0bdaf97802..9770d2f1ef364 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -204,7 +204,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.storage.values.get(vid.index as usize).origin + &self.storage.values.get(vid.as_usize()).origin } /// Records that `a == b`, depending on `dir`. @@ -269,7 +269,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { assert_eq!(eq_key.vid, sub_key); let index = self.values().push(TypeVariableData { origin, diverging }); - assert_eq!(eq_key.vid.index, index as u32); + assert_eq!(eq_key.vid.as_u32(), index as u32); debug!( "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", @@ -357,11 +357,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { &mut self, value_count: usize, ) -> (Range, Vec) { - let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; + let range = TyVid::from_u32(value_count as u32)..TyVid::from_usize(self.num_vars()); ( range.start..range.end, - (range.start.index..range.end.index) - .map(|index| self.storage.values.get(index as usize).origin) + (range.start.as_usize()..range.end.as_usize()) + .map(|index| self.storage.values.get(index).origin) .collect(), ) } @@ -371,7 +371,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn unsolved_variables(&mut self) -> Vec { (0..self.storage.values.len()) .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; + let vid = ty::TyVid::from_usize(i); match self.probe(vid) { TypeVariableValue::Unknown { .. } => Some(vid), TypeVariableValue::Known { .. } => None, @@ -424,10 +424,10 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { type Value = TypeVariableValue<'tcx>; #[inline(always)] fn index(&self) -> u32 { - self.vid.index + self.vid.as_u32() } fn from_index(i: u32) -> Self { - TyVidEqKey::from(ty::TyVid { index: i }) + TyVidEqKey::from(ty::TyVid::from_u32(i)) } fn tag() -> &'static str { "TyVidEqKey" diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 40841a6e32d00..865de7c162320 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1244,7 +1244,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let sig = if let ty::Tuple(inputs) = inputs.kind() { tcx.mk_fn_sig( inputs.iter().map(|k| k.expect_ty()), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), false, hir::Unsafety::Normal, abi::Abi::Rust, @@ -1252,7 +1252,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } else { tcx.mk_fn_sig( std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), + tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))), false, hir::Unsafety::Normal, abi::Abi::Rust, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c405bbe2d1f53..d9ce169efc15c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -363,10 +363,11 @@ pub enum IntVarValue { #[derive(Clone, Copy, PartialEq, Eq)] pub struct FloatVarValue(pub FloatTy); -/// A **ty**pe **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] -pub struct TyVid { - pub index: u32, +rustc_index::newtype_index! { + /// A **ty**pe **v**ariable **ID**. + pub struct TyVid { + DEBUG_FORMAT = "_#{}t" + } } /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. @@ -422,10 +423,10 @@ pub enum InferTy { impl UnifyKey for TyVid { type Value = (); fn index(&self) -> u32 { - self.index + self.as_u32() } fn from_index(i: u32) -> TyVid { - TyVid { index: i } + TyVid::from_u32(i) } fn tag() -> &'static str { "TyVid" @@ -558,7 +559,7 @@ impl HashStable for InferTy { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { use InferTy::*; match self { - TyVar(v) => v.index.hash_stable(ctx, hasher), + TyVar(v) => v.as_u32().hash_stable(ctx, hasher), IntVar(v) => v.index.hash_stable(ctx, hasher), FloatVar(v) => v.index.hash_stable(ctx, hasher), FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher), @@ -587,12 +588,6 @@ impl fmt::Debug for FloatVarValue { } } -impl fmt::Debug for TyVid { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}t", self.index) - } -} - impl fmt::Debug for IntVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "_#{}i", self.index) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index afe274a2a796e..43444492cc748 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -743,7 +743,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let projection_ty = pred.skip_binder().projection_ty; let substs_with_infer_self = tcx.mk_substs( - iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into()) + iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into()) .chain(projection_ty.substs.iter().skip(1)), ); From cf56389b824cc55849776f2a7dc80ba519098f60 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 22 Nov 2020 09:58:58 -0500 Subject: [PATCH 02/17] introduce new fallback algorithm We now fallback type variables using the following rules: * Construct a coercion graph `A -> B` where `A` and `B` are unresolved type variables or the `!` type. * Let D be those variables that are reachable from `!`. * Let N be those variables that are reachable from a variable not in D. * All variables in (D \ N) fallback to `!`. * All variables in (D & N) fallback to `()`. --- compiler/rustc_infer/src/infer/mod.rs | 13 +- compiler/rustc_middle/src/ty/sty.rs | 8 + compiler/rustc_typeck/src/check/fallback.rs | 273 +++++++++++++++--- .../diverging-fallback-control-flow.rs | 35 +-- .../never_type/diverging-fallback-no-leak.rs | 15 + .../diverging-fallback-no-leak.stderr | 11 + ...diverging-fallback-unconstrained-return.rs | 34 +++ 7 files changed, 335 insertions(+), 54 deletions(-) create mode 100644 src/test/ui/never_type/diverging-fallback-no-leak.rs create mode 100644 src/test/ui/never_type/diverging-fallback-no-leak.stderr create mode 100644 src/test/ui/never_type/diverging-fallback-unconstrained-return.rs diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index bc98a3aa3f95e..215aa87278236 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -698,11 +698,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// No attempt is made to resolve `ty`. pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging { match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), + ty::Infer(ty::TyVar(vid)) => self.ty_vid_diverges(vid), _ => Diverging::NotDiverging, } } + /// Returns true if the type inference variable `vid` was created + /// as a diverging type variable. No attempt is made to resolve `vid`. + pub fn ty_vid_diverges(&'a self, vid: ty::TyVid) -> Diverging { + self.inner.borrow_mut().type_variables().var_diverges(vid) + } + /// Returns the origin of the type variable identified by `vid`, or `None` /// if this is not a type variable. /// @@ -1061,6 +1067,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } + /// Number of type variables created so far. + pub fn num_ty_vars(&self) -> usize { + self.inner.borrow_mut().type_variables().num_vars() + } + pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid { self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 65dd61b63295c..c48b768b2513e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1672,6 +1672,14 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Infer(TyVar(_))) } + #[inline] + pub fn ty_vid(&self) -> Option { + match self.kind() { + &Infer(TyVar(vid)) => Some(vid), + _ => None, + } + } + #[inline] pub fn is_ty_infer(&self) -> bool { matches!(self.kind(), Infer(_)) diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 8f6cdc7bb12a7..9f4efc46d67b2 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,4 +1,7 @@ use crate::check::FnCtxt; +use rustc_data_structures::{ + fx::FxHashMap, graph::vec_graph::VecGraph, graph::WithSuccessors, stable_set::FxHashSet, +}; use rustc_infer::infer::type_variable::Diverging; use rustc_middle::ty::{self, Ty}; @@ -10,20 +13,28 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.select_obligations_where_possible(false, |_| {}); let mut fallback_has_occurred = false; + // Check if we have any unsolved varibales. If not, no need for fallback. + let unsolved_variables = self.unsolved_variables(); + if unsolved_variables.is_empty() { + return; + } + + let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + // We do fallback in two passes, to try to generate // better error messages. // The first time, we do *not* replace opaque types. - for ty in &self.unsolved_variables() { + for ty in unsolved_variables { debug!("unsolved_variable = {:?}", ty); - fallback_has_occurred |= self.fallback_if_possible(ty); + fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback); } - // We now see if we can make progress. This might - // cause us to unify inference variables for opaque types, - // since we may have unified some other type variables - // during the first phase of fallback. - // This means that we only replace inference variables with their underlying - // opaque types as a last resort. + // We now see if we can make progress. This might cause us to + // unify inference variables for opaque types, since we may + // have unified some other type variables during the first + // phase of fallback. This means that we only replace + // inference variables with their underlying opaque types as a + // last resort. // // In code like this: // @@ -62,36 +73,44 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // // - Unconstrained floats are replaced with with `f64`. // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. + // - Non-numerics may get replaced with `()` or `!`, depending on + // how they were categorized by `calculate_diverging_fallback` + // (and the setting of `#![feature(never_type_fallback)]`). + // + // Fallback becomes very dubious if we have encountered + // type-checking errors. In that case, fallback to Error. // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool { + fn fallback_if_possible( + &self, + ty: Ty<'tcx>, + diverging_fallback: &FxHashMap, Ty<'tcx>>, + ) -> bool { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` - // is an unsolved variable, and we determine its fallback based - // solely on how it was created, not what other type variables - // it may have been unified with since then. + // is an unsolved variable, and we determine its fallback + // based solely on how it was created, not what other type + // variables it may have been unified with since then. // - // The reason this matters is that other attempts at fallback may - // (in principle) conflict with this fallback, and we wish to generate - // a type error in that case. (However, this actually isn't true right now, - // because we're only using the builtin fallback rules. This would be - // true if we were using user-supplied fallbacks. But it's still useful - // to write the code to detect bugs.) + // The reason this matters is that other attempts at fallback + // may (in principle) conflict with this fallback, and we wish + // to generate a type error in that case. (However, this + // actually isn't true right now, because we're only using the + // builtin fallback rules. This would be true if we were using + // user-supplied fallbacks. But it's still useful to write the + // code to detect bugs.) // - // (Note though that if we have a general type variable `?T` that is then unified - // with an integer type variable `?I` that ultimately never gets - // resolved to a special integral type, `?T` is not considered unsolved, - // but `?I` is. The same is true for float variables.) + // (Note though that if we have a general type variable `?T` + // that is then unified with an integer type variable `?I` + // that ultimately never gets resolved to a special integral + // type, `?T` is not considered unsolved, but `?I` is. The + // same is true for float variables.) let fallback = match ty.kind() { _ if self.is_tainted_by_errors() => self.tcx.ty_error(), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, - _ => match self.type_var_diverges(ty) { - Diverging::Diverges => self.tcx.mk_diverging_default(), - Diverging::NotDiverging => return false, + _ => match diverging_fallback.get(&ty) { + Some(&fallback_ty) => fallback_ty, + None => return false, }, }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); @@ -105,11 +124,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> { true } - /// Second round of fallback: Unconstrained type variables - /// created from the instantiation of an opaque - /// type fall back to the opaque type itself. This is a - /// somewhat incomplete attempt to manage "identity passthrough" - /// for `impl Trait` types. + /// Second round of fallback: Unconstrained type variables created + /// from the instantiation of an opaque type fall back to the + /// opaque type itself. This is a somewhat incomplete attempt to + /// manage "identity passthrough" for `impl Trait` types. /// /// For example, in this code: /// @@ -158,4 +176,191 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } } + + /// The "diverging fallback" system is rather complicated. This is + /// a result of our need to balance 'do the right thing' with + /// backwards compatibility. + /// + /// "Diverging" type variables are variables created when we + /// coerce a `!` type into an unbound type variable `?X`. If they + /// never wind up being constrained, the "right and natural" thing + /// is that `?X` should "fallback" to `!`. This means that e.g. an + /// expression like `Some(return)` will ultimately wind up with a + /// type like `Option` (presuming it is not assigned or + /// constrained to have some other type). + /// + /// However, the fallback used to be `()` (before the `!` type was + /// added). Moreover, there are cases where the `!` type 'leaks + /// out' from dead code into type variables that affect live + /// code. The most common case is something like this: + /// + /// ```rust + /// match foo() { + /// 22 => Default::default(), // call this type `?D` + /// _ => return, // return has type `!` + /// } // call the type of this match `?M` + /// ``` + /// + /// Here, coercing the type `!` into `?M` will create a diverging + /// type variable `?X` where `?X <: ?M`. We also have that `?D <: + /// ?M`. If `?M` winds up unconstrained, then `?X` will + /// fallback. If it falls back to `!`, then all the type variables + /// will wind up equal to `!` -- this includes the type `?D` + /// (since `!` doesn't implement `Default`, we wind up a "trait + /// not implemented" error in code like this). But since the + /// original fallback was `()`, this code used to compile with `?D + /// = ()`. This is somewhat surprising, since `Default::default()` + /// on its own would give an error because the types are + /// insufficiently constrained. + /// + /// Our solution to this dilemma is to modify diverging variables + /// so that they can *either* fallback to `!` (the default) or to + /// `()` (the backwards compatibility case). We decide which + /// fallback to use based on whether there is a coercion pattern + /// like this: + /// + /// ``` + /// ?Diverging -> ?V + /// ?NonDiverging -> ?V + /// ?V != ?NonDiverging + /// ``` + /// + /// Here `?Diverging` represents some diverging type variable and + /// `?NonDiverging` represents some non-diverging type + /// variable. `?V` can be any type variable (diverging or not), so + /// long as it is not equal to `?NonDiverging`. + /// + /// Intuitively, what we are looking for is a case where a + /// "non-diverging" type variable (like `?M` in our example above) + /// is coerced *into* some variable `?V` that would otherwise + /// fallback to `!`. In that case, we make `?V` fallback to `!`, + /// along with anything that would flow into `?V`. + /// + /// The algorithm we use: + /// * Identify all variables that are coerced *into* by a + /// diverging variable. Do this by iterating over each + /// diverging, unsolved variable and finding all variables + /// reachable from there. Call that set `D`. + /// * Walk over all unsolved, non-diverging variables, and find + /// any variable that has an edge into `D`. + fn calculate_diverging_fallback( + &self, + unsolved_variables: &[Ty<'tcx>], + ) -> FxHashMap, Ty<'tcx>> { + debug!("calculate_diverging_fallback({:?})", unsolved_variables); + + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + + // Extract the unsolved type inference variable vids; note that some + // unsolved variables are integer/float variables and are excluded. + let unsolved_vids: Vec<_> = + unsolved_variables.iter().filter_map(|ty| ty.ty_vid()).collect(); + + // Find all type variables that are reachable from a diverging + // type variable. These will typically default to `!`, unless + // we find later that they are *also* reachable from some + // other type variable outside this set. + let mut roots_reachable_from_diverging = FxHashSet::default(); + let mut diverging_vids = vec![]; + let mut non_diverging_vids = vec![]; + for &unsolved_vid in &unsolved_vids { + debug!( + "calculate_diverging_fallback: unsolved_vid={:?} diverges={:?}", + unsolved_vid, + self.infcx.ty_vid_diverges(unsolved_vid) + ); + match self.infcx.ty_vid_diverges(unsolved_vid) { + Diverging::Diverges => { + diverging_vids.push(unsolved_vid); + let root_vid = self.infcx.root_var(unsolved_vid); + debug!( + "calculate_diverging_fallback: root_vid={:?} reaches {:?}", + root_vid, + coercion_graph.depth_first_search(root_vid).collect::>() + ); + roots_reachable_from_diverging + .extend(coercion_graph.depth_first_search(root_vid)); + } + Diverging::NotDiverging => { + non_diverging_vids.push(unsolved_vid); + } + } + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", + roots_reachable_from_diverging, + ); + + // Find all type variables N0 that are not reachable from a + // diverging variable, and then compute the set reachable from + // N0, which we call N. These are the *non-diverging* type + // variables. (Note that this set consists of "root variables".) + let mut roots_reachable_from_non_diverging = FxHashSet::default(); + for &non_diverging_vid in &non_diverging_vids { + let root_vid = self.infcx.root_var(non_diverging_vid); + if roots_reachable_from_diverging.contains(&root_vid) { + continue; + } + roots_reachable_from_non_diverging.extend(coercion_graph.depth_first_search(root_vid)); + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", + roots_reachable_from_non_diverging, + ); + + // For each diverging variable, figure out whether it can + // reach a member of N. If so, it falls back to `()`. Else + // `!`. + let mut diverging_fallback = FxHashMap::default(); + for &diverging_vid in &diverging_vids { + let diverging_ty = self.tcx.mk_ty_var(diverging_vid); + let root_vid = self.infcx.root_var(diverging_vid); + let can_reach_non_diverging = coercion_graph + .depth_first_search(root_vid) + .any(|n| roots_reachable_from_non_diverging.contains(&n)); + if can_reach_non_diverging { + debug!("fallback to (): {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else { + debug!("fallback to !: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); + } + } + + diverging_fallback + } + + /// Returns a graph whose nodes are (unresolved) inference variables and where + /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. + fn create_coercion_graph(&self) -> VecGraph { + let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations(); + debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); + let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations + .into_iter() + .filter_map(|obligation| { + // The predicates we are looking for look like `Coerce(?A -> ?B)`. + // They will have no bound variables. + obligation.predicate.kind().no_bound_vars() + }) + .filter_map(|atom| { + if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom { + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid, b_vid)) + } else { + None + } + }) + .collect(); + debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); + let num_ty_vars = self.infcx.num_ty_vars(); + VecGraph::new(num_ty_vars, coercion_edges) + } + + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) + } } diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs index ea4881049d792..f323f40ba31c6 100644 --- a/src/test/ui/never_type/diverging-fallback-control-flow.rs +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -4,27 +4,24 @@ #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(unreachable_code)] - // Test various cases where we permit an unconstrained variable -// to fallback based on control-flow. -// -// These represent current behavior, but are pretty dubious. I would -// like to revisit these and potentially change them. --nmatsakis - +// to fallback based on control-flow. In all of these cases, +// the type variable winds up being the target of both a `!` coercion +// and a coercion from a non-`!` variable, and hence falls back to `()`. #![feature(never_type, never_type_fallback)] -trait BadDefault { +trait UnitDefault { fn default() -> Self; } -impl BadDefault for u32 { +impl UnitDefault for u32 { fn default() -> Self { 0 } } -impl BadDefault for ! { - fn default() -> ! { +impl UnitDefault for () { + fn default() -> () { panic!() } } @@ -33,7 +30,7 @@ fn assignment() { let x; if true { - x = BadDefault::default(); + x = UnitDefault::default(); } else { x = return; } @@ -45,13 +42,13 @@ fn assignment_rev() { if true { x = return; } else { - x = BadDefault::default(); + x = UnitDefault::default(); } } fn if_then_else() { let _x = if true { - BadDefault::default() + UnitDefault::default() } else { return; }; @@ -61,19 +58,19 @@ fn if_then_else_rev() { let _x = if true { return; } else { - BadDefault::default() + UnitDefault::default() }; } fn match_arm() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Ok(v) => v, Err(()) => return, }; } fn match_arm_rev() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Err(()) => return, Ok(v) => v, }; @@ -84,7 +81,7 @@ fn loop_break() { if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } @@ -94,9 +91,9 @@ fn loop_break_rev() { if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } -fn main() { } +fn main() {} diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.rs b/src/test/ui/never_type/diverging-fallback-no-leak.rs new file mode 100644 index 0000000000000..a3a15f0ed885d --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.rs @@ -0,0 +1,15 @@ +#![feature(never_type_fallback)] + +fn make_unit() {} + +trait Test {} +impl Test for i32 {} +impl Test for () {} + +fn unconstrained_arg(_: T) {} + +fn main() { + // Here the type variable falls back to `!`, + // and hence we get a type error: + unconstrained_arg(return); //~ ERROR trait bound `!: Test` is not satisfied +} diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.stderr new file mode 100644 index 0000000000000..44566dc6bac7b --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `!: Test` is not satisfied + --> $DIR/diverging-fallback-no-leak.rs:14:5 + | +LL | unconstrained_arg(return); + | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` + | + = note: the trait is implemented for `()`. Possibly this error has been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information). Consider whether you meant to use the type `()` here instead. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs new file mode 100644 index 0000000000000..9a6c965cefb09 --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -0,0 +1,34 @@ +// Variant of diverging-falllback-control-flow that tests +// the specific case of a free function with an unconstrained +// return type. This captures the pattern we saw in the wild +// in the objc crate, where changing the fallback from `!` to `()` +// resulted in unsoundness. +// +// check-pass + +#![feature(never_type_fallback)] + +fn make_unit() {} + +trait UnitReturn {} +impl UnitReturn for i32 {} +impl UnitReturn for () {} + +fn unconstrained_return() -> T { + unsafe { + let make_unit_fn: fn() = make_unit; + let ffi: fn() -> T = std::mem::transmute(make_unit_fn); + ffi() + } +} + +fn main() { + // In Ye Olde Days, the `T` parameter of `unconstrained_return` + // winds up "entangled" with the `!` type that results from + // `panic!`, and hence falls back to `()`. This is kind of unfortunate + // and unexpected. When we introduced the `!` type, the original + // idea was to change that fallback to `!`, but that would have resulted + // in this code no longer compiling (or worse, in some cases it injected + // unsound results). + let _ = if true { unconstrained_return() } else { panic!() }; +} From ac195c78ca08d6a589eb4c8a6d4c1af7f20089e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 07:42:06 -0500 Subject: [PATCH 03/17] remove diverging type variables from fn check The comment seems incorrect. Testing revealed that the examples in question still work (as well as some variants) even without the special casing here. --- .../rustc_infer/src/infer/type_variable.rs | 6 +++- compiler/rustc_typeck/src/check/check.rs | 32 +++++-------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 9770d2f1ef364..987af2cb4ee13 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -129,7 +129,11 @@ pub enum TypeVariableOriginKind { SubstitutionPlaceholder, AutoDeref, AdjustmentType, - DivergingFn, + + /// In type check, when we are type checking a function that + /// returns `-> dyn Foo`, we substitute a type variable for the + /// return type for diagnostic purposes. + DynReturnFn, LatticeVariable, } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 3c9d5b4def4e7..c01cf4f2a5a75 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -241,32 +241,16 @@ pub(super) fn check_fn<'a, 'tcx>( // we saw and assigning it to the expected return type. This isn't // really expected to fail, since the coercions would have failed // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). let coercion = fcx.ret_coercion.take().unwrap().into_inner(); let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); + debug!("actual_return_ty = {:?}", actual_return_ty); + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // We have special-cased the case where the function is declared + // `-> dyn Foo` and we don't actually relate it to the + // `fcx.ret_coercion`, so just substitute a type variable. + actual_return_ty = + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); + debug!("actual_return_ty replaced with {:?}", actual_return_ty); } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); From f54591f9ed0b9a915b459c5ea89e6ea8c07c4c65 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 07:43:33 -0500 Subject: [PATCH 04/17] remove reliance on "diverging" type variables Instead, we now record those type variables that are the target of a `NeverToAny` adjustment and consider those to be the "diverging" type variables. This allows us to remove the special case logic that creates a type variable for `!` in coercion. --- compiler/rustc_typeck/src/check/coercion.rs | 19 +------ compiler/rustc_typeck/src/check/fallback.rs | 57 ++++++++++++------- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 9 +++ compiler/rustc_typeck/src/check/inherited.rs | 7 +++ 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 3bfab9d513f37..5ae9041c7b300 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -159,24 +159,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - return if b.is_ty_var() { - // Micro-optimization: no need for this if `b` is - // already resolved in some way. - let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AdjustmentType, - span: self.cause.span, - }); - self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny)) - } else { - success(simple(Adjust::NeverToAny)(b), b, vec![]) - }; + return success(simple(Adjust::NeverToAny)(b), b, vec![]); } // Coercing *from* an unresolved inference variable means that diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 9f4efc46d67b2..c1c3c3034e4bc 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -2,7 +2,6 @@ use crate::check::FnCtxt; use rustc_data_structures::{ fx::FxHashMap, graph::vec_graph::VecGraph, graph::WithSuccessors, stable_set::FxHashSet, }; -use rustc_infer::infer::type_variable::Diverging; use rustc_middle::ty::{self, Ty}; impl<'tcx> FnCtxt<'_, 'tcx> { @@ -255,8 +254,27 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // Extract the unsolved type inference variable vids; note that some // unsolved variables are integer/float variables and are excluded. - let unsolved_vids: Vec<_> = - unsolved_variables.iter().filter_map(|ty| ty.ty_vid()).collect(); + let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid()); + + // Compute the diverging root vids D -- that is, the root vid of + // those type variables that (a) are the target of a coercion from + // a `!` type and (b) have not yet been solved. + // + // These variables are the ones that are targets for fallback to + // either `!` or `()`. + let diverging_roots: FxHashSet = self + .diverging_type_vars + .borrow() + .iter() + .map(|&ty| self.infcx.shallow_resolve(ty)) + .filter_map(|ty| ty.ty_vid()) + .map(|vid| self.infcx.root_var(vid)) + .collect(); + debug!( + "calculate_diverging_fallback: diverging_type_vars={:?}", + self.diverging_type_vars.borrow() + ); + debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots); // Find all type variables that are reachable from a diverging // type variable. These will typically default to `!`, unless @@ -265,27 +283,24 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let mut roots_reachable_from_diverging = FxHashSet::default(); let mut diverging_vids = vec![]; let mut non_diverging_vids = vec![]; - for &unsolved_vid in &unsolved_vids { + for unsolved_vid in unsolved_vids { + let root_vid = self.infcx.root_var(unsolved_vid); debug!( - "calculate_diverging_fallback: unsolved_vid={:?} diverges={:?}", + "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", unsolved_vid, - self.infcx.ty_vid_diverges(unsolved_vid) + root_vid, + diverging_roots.contains(&root_vid), ); - match self.infcx.ty_vid_diverges(unsolved_vid) { - Diverging::Diverges => { - diverging_vids.push(unsolved_vid); - let root_vid = self.infcx.root_var(unsolved_vid); - debug!( - "calculate_diverging_fallback: root_vid={:?} reaches {:?}", - root_vid, - coercion_graph.depth_first_search(root_vid).collect::>() - ); - roots_reachable_from_diverging - .extend(coercion_graph.depth_first_search(root_vid)); - } - Diverging::NotDiverging => { - non_diverging_vids.push(unsolved_vid); - } + if diverging_roots.contains(&root_vid) { + diverging_vids.push(unsolved_vid); + debug!( + "calculate_diverging_fallback: root_vid={:?} reaches {:?}", + root_vid, + coercion_graph.depth_first_search(root_vid).collect::>() + ); + roots_reachable_from_diverging.extend(coercion_graph.depth_first_search(root_vid)); + } else { + non_diverging_vids.push(unsolved_vid); } } debug!( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 25d1c8706e874..2bca8c063a56f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -278,6 +278,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + for a in &adj { + if let Adjust::NeverToAny = a.kind { + if a.target.is_ty_var() { + self.diverging_type_vars.borrow_mut().insert(a.target); + debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + } + } + } + let autoborrow_mut = adj.iter().any(|adj| { matches!( adj, diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 6006c8f7513d7..f7552c1f4eb0c 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,6 +1,7 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; @@ -56,6 +57,11 @@ pub struct Inherited<'a, 'tcx> { pub(super) constness: hir::Constness, pub(super) body_id: Option, + + /// Whenever we introduce an adjustment from `!` into a type variable, + /// we record that type variable here. This is later used to inform + /// fallback. See the `fallback` module for details. + pub(super) diverging_type_vars: RefCell>>, } impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { @@ -121,6 +127,7 @@ impl Inherited<'a, 'tcx> { deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), + diverging_type_vars: RefCell::new(Default::default()), constness, body_id, } From 543b241939ef23e23b8fea68000f135f650f0236 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 09:06:37 -0500 Subject: [PATCH 05/17] stop categorizing inference variables as diverging when created Instead, we now rely on the code that looks for a NeverToAny adjustment. --- compiler/rustc_infer/src/infer/combine.rs | 15 ++++---- compiler/rustc_infer/src/infer/mod.rs | 36 +++---------------- .../rustc_infer/src/infer/nll_relate/mod.rs | 4 +-- .../rustc_infer/src/infer/type_variable.rs | 23 ++---------- compiler/rustc_typeck/src/check/expr.rs | 2 +- 5 files changed, 17 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 32308910aa7d9..310d641e92f19 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -22,6 +22,7 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. +use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; @@ -29,7 +30,6 @@ use super::type_variable::TypeVariableValue; use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use super::{equate::Equate, type_variable::Diverging}; use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; @@ -645,7 +645,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { .inner .borrow_mut() .type_variables() - .new_var(self.for_universe, Diverging::NotDiverging, origin); + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); // Record that we replaced `vid` with `new_var_id` as part of a generalization @@ -885,11 +885,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { let origin = *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( - self.for_universe, - Diverging::NotDiverging, - origin, - ); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!( "ConstInferUnifier: replacing original vid={:?} with new={:?}", diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 215aa87278236..1c7a5d9257fc7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; -use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind}; +use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; pub mod canonical; @@ -692,23 +692,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { t.fold_with(&mut self.freshener()) } - /// Returns whether `ty` is a diverging type variable or not. - /// (If `ty` is not a type variable at all, returns not diverging.) - /// - /// No attempt is made to resolve `ty`. - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging { - match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => self.ty_vid_diverges(vid), - _ => Diverging::NotDiverging, - } - } - - /// Returns true if the type inference variable `vid` was created - /// as a diverging type variable. No attempt is made to resolve `vid`. - pub fn ty_vid_diverges(&'a self, vid: ty::TyVid) -> Diverging { - self.inner.borrow_mut().type_variables().var_diverges(vid) - } - /// Returns the origin of the type variable identified by `vid`, or `None` /// if this is not a type variable. /// @@ -1072,12 +1055,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.inner.borrow_mut().type_variables().num_vars() } - pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) + pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(origin)) } pub fn next_ty_var_in_universe( @@ -1085,18 +1068,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var( - universe, - Diverging::NotDiverging, - origin, - ); + let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin); self.tcx.mk_ty_var(vid) } - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin)) - } - pub fn next_const_var( &self, ty: Ty<'tcx>, @@ -1208,7 +1183,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // as the substitutions for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), - Diverging::NotDiverging, TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition( param.name, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index c211d8e94a68b..637266c1ce3d7 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -22,7 +22,6 @@ //! constituents) use crate::infer::combine::ConstEquateRelation; -use crate::infer::type_variable::Diverging; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use rustc_data_structures::fx::FxHashMap; @@ -927,8 +926,7 @@ where // Replacing with a new variable in the universe `self.universe`, // it will be unified later with the original type variable in // the universe `_universe`. - let new_var_id = - variables.new_var(self.universe, Diverging::NotDiverging, origin); + let new_var_id = variables.new_var(self.universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 987af2cb4ee13..602987e15b68f 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -139,13 +139,6 @@ pub enum TypeVariableOriginKind { pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, - diverging: Diverging, -} - -#[derive(Copy, Clone, Debug)] -pub enum Diverging { - NotDiverging, - Diverges, } #[derive(Copy, Clone, Debug)] @@ -195,14 +188,6 @@ impl<'tcx> TypeVariableStorage<'tcx> { } impl<'tcx> TypeVariableTable<'_, 'tcx> { - /// Returns the diverges flag given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging { - self.storage.values.get(vid.index as usize).diverging - } - /// Returns the origin that was given when `vid` was created. /// /// Note that this function does not return care whether @@ -264,7 +249,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn new_var( &mut self, universe: ty::UniverseIndex, - diverging: Diverging, origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); @@ -272,13 +256,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { let sub_key = self.sub_relations().new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values().push(TypeVariableData { origin, diverging }); + let index = self.values().push(TypeVariableData { origin }); assert_eq!(eq_key.vid.as_u32(), index as u32); - debug!( - "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", - eq_key.vid, universe, diverging, origin, - ); + debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,); eq_key.vid } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 51c646e500ca3..ca3a38457d3e3 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted" ); - let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin { + let adj_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::AdjustmentType, span: expr.span, }); From 141246c7473600ffac6317f95ecc1e17e37acfc5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 09:26:10 -0500 Subject: [PATCH 06/17] fix bug in `DepthFirstSearch` where start node was not visited This could cause us to visit the start node twice. --- compiler/rustc_data_structures/src/graph/iterate/mod.rs | 4 +++- compiler/rustc_data_structures/src/graph/iterate/tests.rs | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 09b91083a6347..987efe1fbee8a 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -84,7 +84,9 @@ where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, { pub fn new(graph: &'graph G, start_node: G::Node) -> Self { - Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) } + let mut visited = BitSet::new_empty(graph.num_nodes()); + visited.insert(start_node); + Self { graph, stack: vec![start_node], visited } } } diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs index 0e038e88b221d..3ee03d8b29214 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs @@ -20,3 +20,11 @@ fn is_cyclic() { assert!(!is_cyclic(&diamond_acyclic)); assert!(is_cyclic(&diamond_cyclic)); } + +#[test] +fn dfs() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + + let result: Vec = DepthFirstSearch::new(&graph, 0).collect(); + assert_eq!(result, vec![0, 2, 3, 1]); +} From c48ee1cf229740c14991d607d64206558a95c00c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 10:21:54 -0500 Subject: [PATCH 07/17] optimization: use a single DepthFirstSearch instead of hashsets Extend the `DepthFirstSearch` iterator so that it can be re-used and extended with add'l start nodes. Then replace the FxHashSets of nodes we were using in the fallback analysis with a single iterator. This way we won't re-walk portions of the graph that are reached more than once, and we also do less allocation etc. --- .../src/graph/iterate/mod.rs | 56 +++++++++++++++++-- .../src/graph/iterate/tests.rs | 10 +++- .../rustc_data_structures/src/graph/mod.rs | 2 +- compiler/rustc_typeck/src/check/fallback.rs | 23 +++++--- 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 987efe1fbee8a..a9db3497b2390 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -83,10 +83,58 @@ impl DepthFirstSearch<'graph, G> where G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, { - pub fn new(graph: &'graph G, start_node: G::Node) -> Self { - let mut visited = BitSet::new_empty(graph.num_nodes()); - visited.insert(start_node); - Self { graph, stack: vec![start_node], visited } + pub fn new(graph: &'graph G) -> Self { + Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) } + } + + /// Version of `push_start_node` that is convenient for chained + /// use. + pub fn with_start_node(mut self, start_node: G::Node) -> Self { + self.push_start_node(start_node); + self + } + + /// Pushes another start node onto the stack. If the node + /// has not already been visited, then you will be able to + /// walk its successors (and so forth) after the current + /// contents of the stack are drained. If multiple start nodes + /// are added into the walk, then their mutual successors + /// will all be walked. You can use this method once the + /// iterator has been completely drained to add additional + /// start nodes. + pub fn push_start_node(&mut self, start_node: G::Node) { + if self.visited.insert(start_node) { + self.stack.push(start_node); + } + } + + /// Searches all nodes reachable from the current start nodes. + /// This is equivalent to just invoke `next` repeatedly until + /// you get a `None` result. + pub fn complete_search(&mut self) { + while let Some(_) = self.next() {} + } + + /// Returns true if node has been visited thus far. + /// A node is considered "visited" once it is pushed + /// onto the internal stack; it may not yet have been yielded + /// from the iterator. This method is best used after + /// the iterator is completely drained. + pub fn visited(&self, node: G::Node) -> bool { + self.visited.contains(node) + } +} + +impl std::fmt::Debug for DepthFirstSearch<'_, G> +where + G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors, +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut f = fmt.debug_set(); + for n in self.visited.iter() { + f.entry(&n); + } + f.finish() } } diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs index 3ee03d8b29214..fbdcb01b5f453 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs @@ -25,6 +25,14 @@ fn is_cyclic() { fn dfs() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); - let result: Vec = DepthFirstSearch::new(&graph, 0).collect(); + let result: Vec = DepthFirstSearch::new(&graph).with_start_node(0).collect(); assert_eq!(result, vec![0, 2, 3, 1]); } + +#[test] +fn dfs_debug() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]); + let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0); + while let Some(_) = dfs.next() {} + assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs)); +} diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index dff22855629a8..3560df6e5e204 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -32,7 +32,7 @@ where where Self: WithNumNodes, { - iterate::DepthFirstSearch::new(self, from) + iterate::DepthFirstSearch::new(self).with_start_node(from) } } diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index c1c3c3034e4bc..8673d6337ab7b 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,6 +1,9 @@ use crate::check::FnCtxt; use rustc_data_structures::{ - fx::FxHashMap, graph::vec_graph::VecGraph, graph::WithSuccessors, stable_set::FxHashSet, + fx::FxHashMap, + graph::WithSuccessors, + graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, }; use rustc_middle::ty::{self, Ty}; @@ -280,7 +283,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // type variable. These will typically default to `!`, unless // we find later that they are *also* reachable from some // other type variable outside this set. - let mut roots_reachable_from_diverging = FxHashSet::default(); + let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph); let mut diverging_vids = vec![]; let mut non_diverging_vids = vec![]; for unsolved_vid in unsolved_vids { @@ -293,16 +296,21 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ); if diverging_roots.contains(&root_vid) { diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.push_start_node(root_vid); + debug!( "calculate_diverging_fallback: root_vid={:?} reaches {:?}", root_vid, coercion_graph.depth_first_search(root_vid).collect::>() ); - roots_reachable_from_diverging.extend(coercion_graph.depth_first_search(root_vid)); + + // drain the iterator to visit all nodes reachable from this node + roots_reachable_from_diverging.complete_search(); } else { non_diverging_vids.push(unsolved_vid); } } + debug!( "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", roots_reachable_from_diverging, @@ -312,13 +320,14 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // diverging variable, and then compute the set reachable from // N0, which we call N. These are the *non-diverging* type // variables. (Note that this set consists of "root variables".) - let mut roots_reachable_from_non_diverging = FxHashSet::default(); + let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); for &non_diverging_vid in &non_diverging_vids { let root_vid = self.infcx.root_var(non_diverging_vid); - if roots_reachable_from_diverging.contains(&root_vid) { + if roots_reachable_from_diverging.visited(root_vid) { continue; } - roots_reachable_from_non_diverging.extend(coercion_graph.depth_first_search(root_vid)); + roots_reachable_from_non_diverging.push_start_node(root_vid); + roots_reachable_from_non_diverging.complete_search(); } debug!( "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", @@ -334,7 +343,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let root_vid = self.infcx.root_var(diverging_vid); let can_reach_non_diverging = coercion_graph .depth_first_search(root_vid) - .any(|n| roots_reachable_from_non_diverging.contains(&n)); + .any(|n| roots_reachable_from_non_diverging.visited(n)); if can_reach_non_diverging { debug!("fallback to (): {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.types.unit); From 9a332c826c10c9a1178a9986c05438beac221cfd Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 25 Apr 2021 22:18:21 -0400 Subject: [PATCH 08/17] stabilize never type --- compiler/rustc_ast_passes/src/feature_gate.rs | 3 - .../example/mini_core_hello_world.rs | 359 ++++++++++++++---- compiler/rustc_feature/src/accepted.rs | 4 + compiler/rustc_feature/src/active.rs | 6 - compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_mir/src/lib.rs | 2 +- compiler/rustc_serialize/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_typeck/src/check/fallback.rs | 3 +- compiler/rustc_typeck/src/lib.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/core/src/clone.rs | 2 +- library/core/src/cmp.rs | 8 +- library/core/src/fmt/mod.rs | 4 +- library/core/src/lib.rs | 2 +- library/core/src/marker.rs | 2 +- library/core/src/num/error.rs | 2 +- library/std/src/error.rs | 2 +- library/std/src/lib.rs | 2 +- library/std/src/primitive_docs.rs | 2 +- src/test/mir-opt/issue-72181-1.rs | 2 +- src/test/mir-opt/remove-never-const.rs | 2 +- src/test/mir-opt/uninhabited-enum.rs | 2 - src/test/ui/asm/noreturn.rs | 2 +- src/test/ui/asm/type-check-2.rs | 2 +- src/test/ui/async-await/async-error-span.rs | 2 +- .../ui/async-await/async-error-span.stderr | 6 +- .../ui/binding/empty-types-in-patterns.rs | 2 +- .../ui/binding/empty-types-in-patterns.stderr | 10 + src/test/ui/borrowck/assign-never-type.rs | 2 +- src/test/ui/break-diverging-value.rs | 2 - src/test/ui/break-diverging-value.stderr | 4 +- src/test/ui/break-while-condition.rs | 2 - src/test/ui/break-while-condition.stderr | 6 +- .../match/pattern-matching-should-fail.rs | 2 - .../coercion/coerce-issue-49593-box-never.rs | 2 +- .../coerce-issue-49593-box-never.stderr | 10 + src/test/ui/coercion/coerce-to-bang-cast.rs | 2 - .../ui/coercion/coerce-to-bang-cast.stderr | 4 +- src/test/ui/coercion/coerce-to-bang.rs | 2 - src/test/ui/coercion/coerce-to-bang.stderr | 20 +- .../min_const_generics/complex-types.rs | 2 - .../min_const_generics/complex-types.stderr | 14 +- src/test/ui/consts/assume-type-intrinsics.rs | 2 +- .../index-out-of-bounds-never-type.rs | 2 +- .../const-eval/panic-assoc-never-type.rs | 2 +- .../ui/consts/const-eval/panic-never-type.rs | 2 +- src/test/ui/consts/const-eval/ub-enum.rs | 2 +- src/test/ui/consts/const-variant-count.rs | 2 +- src/test/ui/consts/validate_never_arrays.rs | 2 +- .../feature-gate-exhaustive-patterns.rs | 2 - .../feature-gate-exhaustive-patterns.stderr | 2 +- .../feature-gates/feature-gate-never_type.rs | 17 - .../feature-gate-never_type.stderr | 48 --- .../ui/for-loop-while/loop-break-value.rs | 2 +- .../intrinsics/panic-uninitialized-zeroed.rs | 5 +- src/test/ui/layout/debug.rs | 2 +- src/test/ui/layout/hexagon-enum.rs | 2 +- src/test/ui/lint/uninitialized-zeroed.rs | 2 +- src/test/ui/lint/unused/must_use-unit.rs | 1 - src/test/ui/lint/unused/must_use-unit.stderr | 6 +- src/test/ui/loops/loop-break-value.rs | 2 - src/test/ui/loops/loop-break-value.stderr | 36 +- src/test/ui/mir/mir_calls_to_shims.rs | 2 +- src/test/ui/never_type/adjust_never.rs | 2 +- src/test/ui/never_type/auto-traits.rs | 2 +- .../call-fn-never-arg-wrong-type.rs | 2 +- src/test/ui/never_type/call-fn-never-arg.rs | 2 +- src/test/ui/never_type/cast-never.rs | 2 +- .../ui/never_type/defaulted-never-note.rs | 2 +- .../ui/never_type/dispatch_from_dyn_zst.rs | 2 +- .../diverging-fallback-control-flow.rs | 2 +- .../diverging-fallback-control-flow.stderr | 10 + .../diverging-fallback-no-leak.stderr | 9 +- ...diverging-fallback-unconstrained-return.rs | 2 +- .../feature-gate-never_type_fallback.rs | 12 - .../feature-gate-never_type_fallback.stderr | 9 - src/test/ui/never_type/impl-for-never.rs | 2 +- src/test/ui/never_type/issue-13352.stderr | 6 +- src/test/ui/never_type/issue-44402.rs | 2 +- src/test/ui/never_type/issue-51506.rs | 2 +- .../ui/never_type/never-assign-dead-code.rs | 2 +- .../ui/never_type/never-assign-wrong-type.rs | 2 +- .../ui/never_type/never-associated-type.rs | 2 +- .../never_type/never-from-impl-is-reserved.rs | 2 +- src/test/ui/never_type/never-result.rs | 2 +- src/test/ui/never_type/never-type-arg.rs | 2 +- src/test/ui/never_type/never-type-rvalues.rs | 2 +- .../never-value-fallback-issue-66757.rs | 5 - .../never-value-fallback-issue-66757.stderr | 10 + .../ui/never_type/never_transmute_never.rs | 2 +- src/test/ui/never_type/try_from.rs | 2 +- .../usefulness/always-inhabited-union-ref.rs | 2 +- .../empty-match.exhaustive_patterns.stderr | 46 +-- .../usefulness/empty-match.normal.stderr | 46 +-- src/test/ui/pattern/usefulness/empty-match.rs | 1 - src/test/ui/pattern/usefulness/uninhabited.rs | 3 +- .../ui/pattern/usefulness/uninhabited.stderr | 10 + src/test/ui/print_type_sizes/uninhabited.rs | 2 +- src/test/ui/reachable/expr_add.rs | 1 - src/test/ui/reachable/expr_add.stderr | 4 +- src/test/ui/reachable/expr_assign.rs | 1 - src/test/ui/reachable/expr_assign.stderr | 8 +- src/test/ui/reachable/expr_call.rs | 1 - src/test/ui/reachable/expr_call.stderr | 6 +- src/test/ui/reachable/expr_cast.rs | 2 +- src/test/ui/reachable/expr_method.rs | 1 - src/test/ui/reachable/expr_method.stderr | 6 +- src/test/ui/reachable/expr_type.rs | 2 +- src/test/ui/reachable/expr_unary.rs | 1 - src/test/ui/reachable/expr_unary.stderr | 6 +- .../ui/reachable/unreachable-loop-patterns.rs | 2 +- .../ui/reachable/unreachable-try-pattern.rs | 2 +- .../ui/reachable/unwarned-match-on-never.rs | 2 +- .../uninhabited/auxiliary/uninhabited.rs | 2 +- .../uninhabited/coercions.rs | 2 +- .../uninhabited/coercions_same_crate.rs | 2 - .../uninhabited/coercions_same_crate.stderr | 8 +- .../uninhabited/indirect_match.rs | 2 +- .../uninhabited/indirect_match_same_crate.rs | 2 - .../indirect_match_same_crate.stderr | 8 +- ...indirect_match_with_exhaustive_patterns.rs | 2 +- ...tch_with_exhaustive_patterns_same_crate.rs | 2 +- .../issue-65157-repeated-match-arm.rs | 2 +- .../uninhabited/match.rs | 2 +- .../uninhabited/match_same_crate.rs | 2 - .../uninhabited/match_same_crate.stderr | 6 +- .../match_with_exhaustive_patterns.rs | 2 +- ...tch_with_exhaustive_patterns_same_crate.rs | 2 +- .../uninhabited/patterns_same_crate.rs | 2 +- .../protect-precedences.rs | 2 +- src/test/ui/statics/uninhabited-static.rs | 1 - src/test/ui/statics/uninhabited-static.stderr | 10 +- src/test/ui/structs-enums/type-sizes.rs | 2 +- .../traits/reservation-impl/non-lattice-ok.rs | 2 +- ..._defining_uses_never_type.full_tait.stderr | 0 .../different_defining_uses_never_type.stderr | 4 +- .../ui/uninhabited/uninhabited-irrefutable.rs | 1 - .../uninhabited-irrefutable.stderr | 2 +- .../ui/uninhabited/uninhabited-patterns.rs | 2 +- .../clippy/clippy_lints/src/empty_enum.rs | 5 - 147 files changed, 575 insertions(+), 434 deletions(-) create mode 100644 src/test/ui/binding/empty-types-in-patterns.stderr create mode 100644 src/test/ui/coercion/coerce-issue-49593-box-never.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-never_type.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-never_type.stderr create mode 100644 src/test/ui/never_type/diverging-fallback-control-flow.stderr delete mode 100644 src/test/ui/never_type/feature-gate-never_type_fallback.rs delete mode 100644 src/test/ui/never_type/feature-gate-never_type_fallback.stderr create mode 100644 src/test/ui/never_type/never-value-fallback-issue-66757.stderr create mode 100644 src/test/ui/pattern/usefulness/uninhabited.stderr create mode 100644 src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 557271e32adb4..f7d3d588b8730 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -437,9 +437,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_extern(bare_fn_ty.ext); } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); - } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 6e13e4dcbfbff..89d7d9adea878 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,11 +1,11 @@ -#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)] +#![feature(no_core, lang_items, linkage, extern_types, thread_local)] #![no_core] #![allow(dead_code, non_camel_case_types)] extern crate mini_core; -use mini_core::*; use mini_core::libc::*; +use mini_core::*; unsafe extern "C" fn my_puts(s: *const i8) { puts(s); @@ -14,7 +14,7 @@ unsafe extern "C" fn my_puts(s: *const i8) { macro_rules! assert { ($e:expr) => { if !$e { - panic(stringify!(! $e)); + panic(stringify!(!$e)); } }; } @@ -24,7 +24,7 @@ macro_rules! assert_eq { if $l != $r { panic(stringify!($l != $r)); } - } + }; } #[lang = "termination"] @@ -88,15 +88,17 @@ enum Ordering { } #[lang = "start"] -fn start( - main: fn() -> T, - argc: isize, - argv: *const *const u8, -) -> isize { +fn start(main: fn() -> T, argc: isize, argv: *const *const u8) -> isize { if argc == 3 { - unsafe { puts(*argv as *const i8); } - unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); } - unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); } + unsafe { + puts(*argv as *const i8); + } + unsafe { + puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const i8)); + } + unsafe { + puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); + } } main().report() as isize @@ -130,10 +132,7 @@ fn call_return_u128_pair() { } fn main() { - take_unique(Unique { - pointer: 0 as *const (), - _marker: PhantomData, - }); + take_unique(Unique { pointer: 0 as *const (), _marker: PhantomData }); take_f32(0.1); call_return_u128_pair(); @@ -176,15 +175,15 @@ fn main() { assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); assert_eq!(intrinsics::min_align_of::() as u8, 2); - assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); + assert_eq!( + intrinsics::min_align_of_val(&a) as u8, + intrinsics::min_align_of::<&str>() as u8 + ); assert!(!intrinsics::needs_drop::()); assert!(intrinsics::needs_drop::()); - Unique { - pointer: 0 as *const &str, - _marker: PhantomData, - } as Unique; + Unique { pointer: 0 as *const &str, _marker: PhantomData } as Unique; struct MyDst(T); @@ -210,19 +209,17 @@ fn main() { } } - let _ = box NoisyDrop { - text: "Boxed outer got dropped!\0", - inner: NoisyDropInner, - } as Box; + let _ = box NoisyDrop { text: "Boxed outer got dropped!\0", inner: NoisyDropInner } + as Box; const FUNC_REF: Option = Some(main); match FUNC_REF { - Some(_) => {}, + Some(_) => {} None => assert!(false), } match Ordering::Less { - Ordering::Less => {}, + Ordering::Less => {} _ => assert!(false), } @@ -238,19 +235,21 @@ fn main() { #[cfg(not(any(jit, windows)))] { - extern { + extern "C" { #[linkage = "extern_weak"] static ABC: *const u8; } { - extern { + extern "C" { #[linkage = "extern_weak"] static ABC: *const u8; } } - unsafe { assert_eq!(ABC as usize, 0); } + unsafe { + assert_eq!(ABC as usize, 0); + } } &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>; @@ -342,13 +341,10 @@ extern "C" { native: *mut pthread_t, attr: *const pthread_attr_t, f: extern "C" fn(_: *mut c_void) -> *mut c_void, - value: *mut c_void + value: *mut c_void, ) -> c_int; - fn pthread_join( - native: pthread_t, - value: *mut *mut c_void - ) -> c_int; + fn pthread_join(native: pthread_t, value: *mut *mut c_void) -> c_int; } #[thread_local] @@ -357,7 +353,9 @@ static mut TLS: u8 = 42; #[cfg(not(jit))] extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void { - unsafe { TLS = 0; } + unsafe { + TLS = 0; + } 0 as *mut c_void } @@ -407,44 +405,267 @@ pub enum E1 { pub enum E2 { V1 { f: bool }, - /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), - _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), - _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), - _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), - _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), - _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), - _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), - _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), - _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), - _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), - _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), - _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), - _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), - _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), - _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), - _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), - _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), - _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), - _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), - _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), - _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), - _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), - _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), - _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), - _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), - _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), - _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), - _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), - _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), - _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), - _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), - _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + /*_00*/ _01(X), + _02(X), + _03(X), + _04(X), + _05(X), + _06(X), + _07(X), + _08(X), + _09(X), + _0A(X), + _0B(X), + _0C(X), + _0D(X), + _0E(X), + _0F(X), + _10(X), + _11(X), + _12(X), + _13(X), + _14(X), + _15(X), + _16(X), + _17(X), + _18(X), + _19(X), + _1A(X), + _1B(X), + _1C(X), + _1D(X), + _1E(X), + _1F(X), + _20(X), + _21(X), + _22(X), + _23(X), + _24(X), + _25(X), + _26(X), + _27(X), + _28(X), + _29(X), + _2A(X), + _2B(X), + _2C(X), + _2D(X), + _2E(X), + _2F(X), + _30(X), + _31(X), + _32(X), + _33(X), + _34(X), + _35(X), + _36(X), + _37(X), + _38(X), + _39(X), + _3A(X), + _3B(X), + _3C(X), + _3D(X), + _3E(X), + _3F(X), + _40(X), + _41(X), + _42(X), + _43(X), + _44(X), + _45(X), + _46(X), + _47(X), + _48(X), + _49(X), + _4A(X), + _4B(X), + _4C(X), + _4D(X), + _4E(X), + _4F(X), + _50(X), + _51(X), + _52(X), + _53(X), + _54(X), + _55(X), + _56(X), + _57(X), + _58(X), + _59(X), + _5A(X), + _5B(X), + _5C(X), + _5D(X), + _5E(X), + _5F(X), + _60(X), + _61(X), + _62(X), + _63(X), + _64(X), + _65(X), + _66(X), + _67(X), + _68(X), + _69(X), + _6A(X), + _6B(X), + _6C(X), + _6D(X), + _6E(X), + _6F(X), + _70(X), + _71(X), + _72(X), + _73(X), + _74(X), + _75(X), + _76(X), + _77(X), + _78(X), + _79(X), + _7A(X), + _7B(X), + _7C(X), + _7D(X), + _7E(X), + _7F(X), + _80(X), + _81(X), + _82(X), + _83(X), + _84(X), + _85(X), + _86(X), + _87(X), + _88(X), + _89(X), + _8A(X), + _8B(X), + _8C(X), + _8D(X), + _8E(X), + _8F(X), + _90(X), + _91(X), + _92(X), + _93(X), + _94(X), + _95(X), + _96(X), + _97(X), + _98(X), + _99(X), + _9A(X), + _9B(X), + _9C(X), + _9D(X), + _9E(X), + _9F(X), + _A0(X), + _A1(X), + _A2(X), + _A3(X), + _A4(X), + _A5(X), + _A6(X), + _A7(X), + _A8(X), + _A9(X), + _AA(X), + _AB(X), + _AC(X), + _AD(X), + _AE(X), + _AF(X), + _B0(X), + _B1(X), + _B2(X), + _B3(X), + _B4(X), + _B5(X), + _B6(X), + _B7(X), + _B8(X), + _B9(X), + _BA(X), + _BB(X), + _BC(X), + _BD(X), + _BE(X), + _BF(X), + _C0(X), + _C1(X), + _C2(X), + _C3(X), + _C4(X), + _C5(X), + _C6(X), + _C7(X), + _C8(X), + _C9(X), + _CA(X), + _CB(X), + _CC(X), + _CD(X), + _CE(X), + _CF(X), + _D0(X), + _D1(X), + _D2(X), + _D3(X), + _D4(X), + _D5(X), + _D6(X), + _D7(X), + _D8(X), + _D9(X), + _DA(X), + _DB(X), + _DC(X), + _DD(X), + _DE(X), + _DF(X), + _E0(X), + _E1(X), + _E2(X), + _E3(X), + _E4(X), + _E5(X), + _E6(X), + _E7(X), + _E8(X), + _E9(X), + _EA(X), + _EB(X), + _EC(X), + _ED(X), + _EE(X), + _EF(X), + _F0(X), + _F1(X), + _F2(X), + _F3(X), + _F4(X), + _F5(X), + _F6(X), + _F7(X), + _F8(X), + _F9(X), + _FA(X), + _FB(X), + _FC(X), + _FD(X), + _FE(X), + _FF(X), V3, V4, } -fn check_niche_behavior () { +fn check_niche_behavior() { if let E1::V2 { .. } = (E1::V1 { f: true }) { intrinsics::abort(); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 18294dfad240d..10e6df687a1e3 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -296,6 +296,10 @@ declare_features! ( (accepted, const_fn_union, "1.56.0", Some(51909), None), /// Allows explicit discriminants on non-unit enum variants. (accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None), + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + (accepted, never_type, "1.60.0", Some(35121), None), + /// Allows diverging expressions to fall back to `!` rather than `()`. + (accepted, never_type_fallback, "1.60.0", Some(65992), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5ae106353da61..bb5a323664fb0 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -334,9 +334,6 @@ declare_features! ( /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), - /// Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", Some(51085), None), @@ -494,9 +491,6 @@ declare_features! ( /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (active, raw_ref_op, "1.41.0", Some(64490), None), - /// Allows diverging expressions to fall back to `!` rather than `()`. - (active, never_type_fallback, "1.41.0", Some(65992), None), - /// Allows using the `#[register_attr]` attribute. (active, register_attr, "1.41.0", Some(66080), None), diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index a4cfaddeeb96f..1fb58587fa04e 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -17,7 +17,7 @@ #![feature(box_patterns)] #![feature(extend_one)] #![feature(iter_zip)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(in_band_lifetimes)] #![feature(control_flow_enum)] #![feature(min_specialization)] diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 24ac723f2c913..e992f4a83587b 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -34,7 +34,7 @@ #![feature(format_args_capture)] #![feature(iter_order_by)] #![feature(iter_zip)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(control_flow_enum)] #![recursion_limit = "256"] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 2c9bad7e5cedb..1a7d9cf147ea1 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -7,7 +7,7 @@ #![feature(proc_macro_internals)] #![feature(min_specialization)] #![feature(try_blocks)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![recursion_limit = "256"] extern crate proc_macro; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 573fa913d680a..09a90c46c6611 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -32,7 +32,7 @@ #![feature(core_intrinsics)] #![feature(discriminant_kind)] #![feature(if_let_guard)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(extern_types)] #![feature(new_uninit)] #![feature(nll)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 89542a1ebabe2..f99f8d70f023b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2375,7 +2375,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { self.types.never } else { self.types.unit } + self.types.never } #[inline] diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index e439a247c7f6c..2741543d8234b 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -16,7 +16,7 @@ Rust MIR: a lowered representation of Rust. #![feature(exact_size_is_empty)] #![feature(format_args_capture)] #![feature(iter_zip)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(map_try_insert)] #![feature(min_specialization)] #![feature(slice_ptr_get)] diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index b31fbab20ac92..4d46994a4e794 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -9,7 +9,7 @@ Core encoding and decoding interfaces. html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(associated_type_bounds)] #![feature(min_specialization)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 220c9f7e2ec2b..e42d0afa03693 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -88,7 +88,7 @@ //! DefPaths which are much more robust in the face of changes to the code base. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index e75c52555b903..5465416ce2a3e 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -10,7 +10,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(nll)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] #![feature(min_specialization)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 017a7c45bbf9d..bd0e44bd7714b 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -17,7 +17,7 @@ #![feature(hash_drain_filter)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(crate_visibility_modifier)] #![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 8673d6337ab7b..c5659bb993358 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -76,8 +76,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // - Unconstrained floats are replaced with with `f64`. // // - Non-numerics may get replaced with `()` or `!`, depending on - // how they were categorized by `calculate_diverging_fallback` - // (and the setting of `#![feature(never_type_fallback)]`). + // how they were categorized by `calculate_diverging_fallback`. // // Fallback becomes very dubious if we have encountered // type-checking errors. In that case, fallback to Error. diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 749f681e92ed1..0e2e491a017b5 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -66,7 +66,7 @@ This API is completely unstable and subject to change. #![feature(iter_zip)] #![feature(nll)] #![feature(try_blocks)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(slice_partition_dedup)] #![feature(control_flow_enum)] #![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 1a387f291ccf4..b010b4eef50f9 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -116,7 +116,7 @@ #![feature(lang_items)] #![feature(layout_for_ptr)] #![feature(negative_impls)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(auto_traits)] diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 19faf9cddac6f..a92fd93a2cf38 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -195,7 +195,7 @@ mod impls { bool char } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.53.0")] impl Clone for ! { #[inline] fn clone(&self) -> Self { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 79610bb409d37..256cf3fd7601d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1357,24 +1357,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.53.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.53.0")] impl Eq for ! {} - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.53.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.53.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 1d75ac3d254bd..1b512579389a9 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2083,14 +2083,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.53.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter<'_>) -> Result { *self } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.53.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter<'_>) -> Result { *self diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1a6d1aed2fd1e..ae9480830acca 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -143,7 +143,6 @@ #![feature(llvm_asm)] #![feature(min_specialization)] #![feature(negative_impls)] -#![feature(never_type)] #![feature(no_core)] #![feature(no_coverage)] // rust-lang/rust#84605 #![feature(no_niche)] // rust-lang/rust#68303 @@ -160,6 +159,7 @@ #![feature(try_blocks)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] +#![cfg_attr(bootstrap, feature(never_type))] // // Target features: #![feature(aarch64_target_feature)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 333f81ce4cfc4..d9371ebc75d55 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -819,7 +819,7 @@ mod copy_impls { bool char } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.53.0")] impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index cdeba9c079273..5ddd0abcf15d3 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -35,7 +35,7 @@ impl From for TryFromIntError { } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.53.0")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { // Match rather than coerce to make sure that code like diff --git a/library/std/src/error.rs b/library/std/src/error.rs index ec9f012295000..f79321f9c0663 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -385,7 +385,7 @@ impl<'a> From> for Box { } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.53.0")] impl Error for ! {} #[unstable( diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 028a066b5a130..766daaceb1164 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -297,7 +297,7 @@ #![feature(min_specialization)] #![feature(needs_panic_runtime)] #![feature(negative_impls)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(new_uninit)] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index dc4572cd9363b..922e7adee9ed1 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -265,7 +265,7 @@ mod prim_bool {} /// [`Debug`]: fmt::Debug /// [`default()`]: Default::default /// -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.53.0")] mod prim_never {} #[doc(primitive = "char")] diff --git a/src/test/mir-opt/issue-72181-1.rs b/src/test/mir-opt/issue-72181-1.rs index 91e98adbe8049..a410fe3d1c519 100644 --- a/src/test/mir-opt/issue-72181-1.rs +++ b/src/test/mir-opt/issue-72181-1.rs @@ -1,7 +1,7 @@ // compile-flags: -Z mir-opt-level=1 // Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags. -#![feature(never_type)] + #![allow(unused, invalid_value)] enum Void {} diff --git a/src/test/mir-opt/remove-never-const.rs b/src/test/mir-opt/remove-never-const.rs index 1673f14b45ce4..7d2fd5e18c9fd 100644 --- a/src/test/mir-opt/remove-never-const.rs +++ b/src/test/mir-opt/remove-never-const.rs @@ -6,7 +6,7 @@ // compile-flags: --emit mir,link #![feature(const_panic)] -#![feature(never_type)] + #![warn(const_err)] struct PrintName(T); diff --git a/src/test/mir-opt/uninhabited-enum.rs b/src/test/mir-opt/uninhabited-enum.rs index 97c6e8cd53111..ff35948829b5c 100644 --- a/src/test/mir-opt/uninhabited-enum.rs +++ b/src/test/mir-opt/uninhabited-enum.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - pub enum Void {} // EMIT_MIR uninhabited_enum.process_never.SimplifyLocals.after.mir diff --git a/src/test/ui/asm/noreturn.rs b/src/test/ui/asm/noreturn.rs index 5e1ee93bfb073..8768cad0c6bce 100644 --- a/src/test/ui/asm/noreturn.rs +++ b/src/test/ui/asm/noreturn.rs @@ -1,7 +1,7 @@ // only-x86_64 // check-pass -#![feature(asm, never_type)] +#![feature(asm)] #![crate_type = "rlib"] pub unsafe fn asm1() { diff --git a/src/test/ui/asm/type-check-2.rs b/src/test/ui/asm/type-check-2.rs index c70a8802814f7..6907e9b6943f7 100644 --- a/src/test/ui/asm/type-check-2.rs +++ b/src/test/ui/asm/type-check-2.rs @@ -1,6 +1,6 @@ // only-x86_64 -#![feature(asm, repr_simd, never_type)] +#![feature(asm, repr_simd)] #[repr(simd)] struct SimdNonCopy(f32, f32, f32, f32); diff --git a/src/test/ui/async-await/async-error-span.rs b/src/test/ui/async-await/async-error-span.rs index 86d459bf084b1..37caa07f5a00b 100644 --- a/src/test/ui/async-await/async-error-span.rs +++ b/src/test/ui/async-await/async-error-span.rs @@ -5,7 +5,7 @@ use std::future::Future; fn get_future() -> impl Future { -//~^ ERROR `()` is not a future +//~^ ERROR `!` is not a future panic!() } diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index 994bfd33ba42e..a25c91f8b598f 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -1,10 +1,10 @@ -error[E0277]: `()` is not a future +error[E0277]: `!` is not a future --> $DIR/async-error-span.rs:7:20 | LL | fn get_future() -> impl Future { - | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future + | ^^^^^^^^^^^^^^^^^^^^^^^^ `!` is not a future | - = help: the trait `Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `!` error[E0698]: type inside `async fn` body must be known in this context --> $DIR/async-error-span.rs:13:9 diff --git a/src/test/ui/binding/empty-types-in-patterns.rs b/src/test/ui/binding/empty-types-in-patterns.rs index 0d0dbcaf40f43..5b9b721e99f97 100644 --- a/src/test/ui/binding/empty-types-in-patterns.rs +++ b/src/test/ui/binding/empty-types-in-patterns.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(never_type, never_type_fallback)] + #![feature(exhaustive_patterns)] #![allow(unreachable_patterns)] diff --git a/src/test/ui/binding/empty-types-in-patterns.stderr b/src/test/ui/binding/empty-types-in-patterns.stderr new file mode 100644 index 0000000000000..bac952981e3b4 --- /dev/null +++ b/src/test/ui/binding/empty-types-in-patterns.stderr @@ -0,0 +1,10 @@ +warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable + --> $DIR/empty-types-in-patterns.rs:3:12 + | +LL | #![feature(never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/borrowck/assign-never-type.rs b/src/test/ui/borrowck/assign-never-type.rs index 4f30ea1467023..c71aac0156ff6 100644 --- a/src/test/ui/borrowck/assign-never-type.rs +++ b/src/test/ui/borrowck/assign-never-type.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + pub fn main() { loop { diff --git a/src/test/ui/break-diverging-value.rs b/src/test/ui/break-diverging-value.rs index d070fddaffc19..1f8995736ec3c 100644 --- a/src/test/ui/break-diverging-value.rs +++ b/src/test/ui/break-diverging-value.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn loop_break_return() -> i32 { let loop_value = loop { break return 0 }; // ok } diff --git a/src/test/ui/break-diverging-value.stderr b/src/test/ui/break-diverging-value.stderr index 69edcd2408002..e4f2f3dd7f692 100644 --- a/src/test/ui/break-diverging-value.stderr +++ b/src/test/ui/break-diverging-value.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/break-diverging-value.rs:11:26 + --> $DIR/break-diverging-value.rs:9:26 | LL | fn loop_break_break() -> i32 { | ---------------- ^^^ expected `i32`, found `()` @@ -7,7 +7,7 @@ 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:23:25 | LL | fn loop_break_void() -> i32 { | --------------- ^^^ expected `i32`, found `()` diff --git a/src/test/ui/break-while-condition.rs b/src/test/ui/break-while-condition.rs index 6064e6ab00235..7aa5682b923a6 100644 --- a/src/test/ui/break-while-condition.rs +++ b/src/test/ui/break-while-condition.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn main() { // The `if false` expressions are simply to // make sure we don't avoid checking everything diff --git a/src/test/ui/break-while-condition.stderr b/src/test/ui/break-while-condition.stderr index 6960c4fd86735..bbc9f21edb06e 100644 --- a/src/test/ui/break-while-condition.stderr +++ b/src/test/ui/break-while-condition.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/break-while-condition.rs:9:20 + --> $DIR/break-while-condition.rs:7:20 | LL | let _: ! = { | ____________________^ @@ -11,7 +11,7 @@ LL | | }; found unit type `()` error[E0308]: mismatched types - --> $DIR/break-while-condition.rs:16:13 + --> $DIR/break-while-condition.rs:14:13 | LL | / while false { LL | | break @@ -22,7 +22,7 @@ LL | | } found unit type `()` error[E0308]: mismatched types - --> $DIR/break-while-condition.rs:24:13 + --> $DIR/break-while-condition.rs:22:13 | LL | / while false { LL | | return diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs index 0f288ffa95a87..27b257d0124bf 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs +++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs @@ -1,7 +1,5 @@ // edition:2021 -#![feature(never_type)] - // Should fake read the discriminant and throw an error fn test1() { let x: !; diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs index 0824ce8cd585b..b71c3663a4f63 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(never_type, never_type_fallback)] + #![allow(unreachable_code)] use std::error::Error; diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never.stderr new file mode 100644 index 0000000000000..91df00ef39fe0 --- /dev/null +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.stderr @@ -0,0 +1,10 @@ +warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable + --> $DIR/coerce-issue-49593-box-never.rs:2:12 + | +LL | #![feature(never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/coercion/coerce-to-bang-cast.rs b/src/test/ui/coercion/coerce-to-bang-cast.rs index 85598a42eccd9..7fb9235ea3669 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.rs +++ b/src/test/ui/coercion/coerce-to-bang-cast.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn cast_a() { let y = {return; 22} as !; //~^ ERROR non-primitive cast diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr index 50e009aa25bb1..92d798ac12c15 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.stderr +++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr @@ -1,11 +1,11 @@ error[E0605]: non-primitive cast: `i32` as `!` - --> $DIR/coerce-to-bang-cast.rs:4:13 + --> $DIR/coerce-to-bang-cast.rs:2:13 | LL | let y = {return; 22} as !; | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `i32` as `!` - --> $DIR/coerce-to-bang-cast.rs:9:13 + --> $DIR/coerce-to-bang-cast.rs:7:13 | LL | let y = 22 as !; | ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/src/test/ui/coercion/coerce-to-bang.rs b/src/test/ui/coercion/coerce-to-bang.rs index 1e06934d09f9e..d52f79fbb7a98 100644 --- a/src/test/ui/coercion/coerce-to-bang.rs +++ b/src/test/ui/coercion/coerce-to-bang.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { diff --git a/src/test/ui/coercion/coerce-to-bang.stderr b/src/test/ui/coercion/coerce-to-bang.stderr index 390aa7c692d18..ca42705973750 100644 --- a/src/test/ui/coercion/coerce-to-bang.stderr +++ b/src/test/ui/coercion/coerce-to-bang.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:6:17 + --> $DIR/coerce-to-bang.rs:4:17 | LL | foo(return, 22, 44); | ^^ expected `!`, found integer @@ -8,7 +8,7 @@ LL | foo(return, 22, 44); found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:18:13 + --> $DIR/coerce-to-bang.rs:16:13 | LL | foo(22, 44, return); | ^^ expected `!`, found integer @@ -17,7 +17,7 @@ LL | foo(22, 44, return); found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:26:12 + --> $DIR/coerce-to-bang.rs:24:12 | LL | foo(a, b, c); // ... and hence a reference to `a` is expected to diverge. | ^ expected `!`, found integer @@ -26,7 +26,7 @@ LL | foo(a, b, c); // ... and hence a reference to `a` is expected to diverg found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:36:12 + --> $DIR/coerce-to-bang.rs:34:12 | LL | foo(a, b, c); | ^ expected `!`, found integer @@ -35,7 +35,7 @@ LL | foo(a, b, c); found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:45:12 + --> $DIR/coerce-to-bang.rs:43:12 | LL | foo(a, b, c); | ^ expected `!`, found integer @@ -44,7 +44,7 @@ LL | foo(a, b, c); found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:50:21 + --> $DIR/coerce-to-bang.rs:48:21 | LL | let x: [!; 2] = [return, 22]; | ------ ^^^^^^^^^^^^ expected `!`, found integer @@ -55,7 +55,7 @@ LL | let x: [!; 2] = [return, 22]; found array `[{integer}; 2]` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:55:22 + --> $DIR/coerce-to-bang.rs:53:22 | LL | let x: [!; 2] = [22, return]; | ^^ expected `!`, found integer @@ -64,7 +64,7 @@ LL | let x: [!; 2] = [22, return]; found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:60:37 + --> $DIR/coerce-to-bang.rs:58:37 | LL | let x: (usize, !, usize) = (22, 44, 66); | ^^ expected `!`, found integer @@ -73,7 +73,7 @@ LL | let x: (usize, !, usize) = (22, 44, 66); found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:65:41 + --> $DIR/coerce-to-bang.rs:63:41 | LL | let x: (usize, !, usize) = (return, 44, 66); | ^^ expected `!`, found integer @@ -82,7 +82,7 @@ LL | let x: (usize, !, usize) = (return, 44, 66); found type `{integer}` error[E0308]: mismatched types - --> $DIR/coerce-to-bang.rs:76:37 + --> $DIR/coerce-to-bang.rs:74:37 | LL | let x: (usize, !, usize) = (22, 44, return); | ^^ expected `!`, found integer diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.rs b/src/test/ui/const-generics/min_const_generics/complex-types.rs index 057bd5af89ef7..f3d103d46ce65 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-types.rs +++ b/src/test/ui/const-generics/min_const_generics/complex-types.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - struct Foo; //~^ ERROR `[u8; 0]` is forbidden diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.stderr b/src/test/ui/const-generics/min_const_generics/complex-types.stderr index a658a7b395689..faa5e0f8a753a 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-types.stderr +++ b/src/test/ui/const-generics/min_const_generics/complex-types.stderr @@ -1,5 +1,5 @@ error: `[u8; 0]` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:3:21 + --> $DIR/complex-types.rs:1:21 | LL | struct Foo; | ^^^^^^^ @@ -8,7 +8,7 @@ LL | struct Foo; = help: more complex types are supported with `#![feature(const_generics)]` error: `()` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:6:21 + --> $DIR/complex-types.rs:4:21 | LL | struct Bar; | ^^ @@ -17,7 +17,7 @@ LL | struct Bar; = help: more complex types are supported with `#![feature(const_generics)]` error: `No` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:11:21 + --> $DIR/complex-types.rs:9:21 | LL | struct Fez; | ^^ @@ -26,7 +26,7 @@ LL | struct Fez; = help: more complex types are supported with `#![feature(const_generics)]` error: `&'static u8` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:14:21 + --> $DIR/complex-types.rs:12:21 | LL | struct Faz; | ^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | struct Faz; = help: more complex types are supported with `#![feature(const_generics)]` error: `!` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:17:21 + --> $DIR/complex-types.rs:15:21 | LL | struct Fiz; | ^ @@ -44,7 +44,7 @@ LL | struct Fiz; = help: more complex types are supported with `#![feature(const_generics)]` error: `()` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:20:19 + --> $DIR/complex-types.rs:18:19 | LL | enum Goo { A, B } | ^^ @@ -53,7 +53,7 @@ LL | enum Goo { A, B } = help: more complex types are supported with `#![feature(const_generics)]` error: `()` is forbidden as the type of a const generic parameter - --> $DIR/complex-types.rs:23:20 + --> $DIR/complex-types.rs:21:20 | LL | union Boo { a: () } | ^^ diff --git a/src/test/ui/consts/assume-type-intrinsics.rs b/src/test/ui/consts/assume-type-intrinsics.rs index 77370e1ccc59e..5023606471539 100644 --- a/src/test/ui/consts/assume-type-intrinsics.rs +++ b/src/test/ui/consts/assume-type-intrinsics.rs @@ -1,6 +1,6 @@ // error-pattern: any use of this value will cause an error -#![feature(never_type)] + #![feature(const_maybe_uninit_assume_init)] #[allow(invalid_value)] diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs index 8064cc49359ee..54c48b812a0f4 100644 --- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -2,7 +2,7 @@ // Regression test for #66975 #![warn(const_err, unconditional_panic)] -#![feature(never_type)] + struct PrintName(T); diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs index ab0256a986dbc..94ff55b198a7c 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -3,7 +3,7 @@ // Regression test for #66975 #![warn(const_err)] #![feature(const_panic)] -#![feature(never_type)] + struct PrintName; diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs index dd875768b168f..58e6fc056fbe0 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -1,7 +1,7 @@ // Regression test for #66975 #![warn(const_err)] #![feature(const_panic)] -#![feature(never_type)] + const VOID: ! = panic!(); //~^ ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index e408d8ec072e3..790fecaf4cf0a 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,7 +1,7 @@ // stderr-per-bitwidth -#![feature(never_type)] #![allow(const_err)] // make sure we cannot allow away the errors tested here + use std::mem; #[repr(transparent)] diff --git a/src/test/ui/consts/const-variant-count.rs b/src/test/ui/consts/const-variant-count.rs index 455419d2c7f1d..35a2500b9fc09 100644 --- a/src/test/ui/consts/const-variant-count.rs +++ b/src/test/ui/consts/const-variant-count.rs @@ -1,7 +1,7 @@ // run-pass #![allow(dead_code)] #![feature(variant_count)] -#![feature(never_type)] + use std::mem::variant_count; diff --git a/src/test/ui/consts/validate_never_arrays.rs b/src/test/ui/consts/validate_never_arrays.rs index 1990fb073970e..0b13e054d5c88 100644 --- a/src/test/ui/consts/validate_never_arrays.rs +++ b/src/test/ui/consts/validate_never_arrays.rs @@ -1,5 +1,5 @@ // stderr-per-bitwidth -#![feature(const_raw_ptr_deref, never_type)] +#![feature(const_raw_ptr_deref)] const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior const _: &[!; 0] = unsafe { &*(1_usize as *const [!; 0]) }; // ok diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs index f0cc9ea70550e..c27089d2a0590 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn foo() -> Result { Ok(123) } diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index c5ffa55ebec6f..e33b66df0c3b8 100644 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered - --> $DIR/feature-gate-exhaustive-patterns.rs:8:9 + --> $DIR/feature-gate-exhaustive-patterns.rs:6:9 | LL | let Ok(_x) = foo(); | ^^^^^^ pattern `Err(_)` not covered diff --git a/src/test/ui/feature-gates/feature-gate-never_type.rs b/src/test/ui/feature-gates/feature-gate-never_type.rs deleted file mode 100644 index be8c27dbb1b02..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-never_type.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Test that ! errors when used in illegal positions with feature(never_type) disabled - -trait Foo { - type Wub; -} - -type Ma = (u32, !, i32); //~ ERROR type is experimental -type Meeshka = Vec; //~ ERROR type is experimental -type Mow = &'static fn(!) -> !; //~ ERROR type is experimental -type Skwoz = &'static mut !; //~ ERROR type is experimental - -impl Foo for Meeshka { - type Wub = !; //~ ERROR type is experimental -} - -fn main() { -} diff --git a/src/test/ui/feature-gates/feature-gate-never_type.stderr b/src/test/ui/feature-gates/feature-gate-never_type.stderr deleted file mode 100644 index 0a59cae9c8c46..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-never_type.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:7:17 - | -LL | type Ma = (u32, !, i32); - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:8:20 - | -LL | type Meeshka = Vec; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:9:24 - | -LL | type Mow = &'static fn(!) -> !; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:10:27 - | -LL | type Skwoz = &'static mut !; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error[E0658]: the `!` type is experimental - --> $DIR/feature-gate-never_type.rs:13:16 - | -LL | type Wub = !; - | ^ - | - = note: see issue #35121 for more information - = help: add `#![feature(never_type)]` to the crate attributes to enable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/for-loop-while/loop-break-value.rs b/src/test/ui/for-loop-while/loop-break-value.rs index d7209fc4de867..e629ce48b994d 100644 --- a/src/test/ui/for-loop-while/loop-break-value.rs +++ b/src/test/ui/for-loop-while/loop-break-value.rs @@ -1,7 +1,7 @@ // run-pass #![allow(unreachable_code)] -#![feature(never_type)] + #[allow(unused)] fn never_returns() { diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 88ef8182f0238..a87f2d957df56 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -3,11 +3,10 @@ // revisions: mir thir // [thir]compile-flags: -Zthir-unsafeck -// This test checks panic emitted from `mem::{uninitialized,zeroed}`. - -#![feature(never_type)] #![allow(deprecated, invalid_value)] +// This test checks panic emitted from `mem::{uninitialized,zeroed}`. + use std::{ mem::{self, MaybeUninit, ManuallyDrop}, panic, diff --git a/src/test/ui/layout/debug.rs b/src/test/ui/layout/debug.rs index 299151df66493..7f39b2beef7d6 100644 --- a/src/test/ui/layout/debug.rs +++ b/src/test/ui/layout/debug.rs @@ -1,5 +1,5 @@ // normalize-stderr-test "pref: Align \{\n *pow2: [1-3],\n *\}" -> "pref: $$PREF_ALIGN" -#![feature(never_type, rustc_attrs, type_alias_impl_trait)] +#![feature(rustc_attrs, type_alias_impl_trait)] #![crate_type = "lib"] #[rustc_layout(debug)] diff --git a/src/test/ui/layout/hexagon-enum.rs b/src/test/ui/layout/hexagon-enum.rs index 4c58537e309ea..f3997177b374c 100644 --- a/src/test/ui/layout/hexagon-enum.rs +++ b/src/test/ui/layout/hexagon-enum.rs @@ -4,7 +4,7 @@ // Verify that the hexagon targets implement the repr(C) for enums correctly. // // See #82100 -#![feature(never_type, rustc_attrs, no_core, lang_items)] +#![feature(rustc_attrs, no_core, lang_items)] #![crate_type = "lib"] #![no_core] diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/uninitialized-zeroed.rs index 122933c3c4e46..3e9551fcc58e4 100644 --- a/src/test/ui/lint/uninitialized-zeroed.rs +++ b/src/test/ui/lint/uninitialized-zeroed.rs @@ -1,7 +1,7 @@ // This test checks that calling `mem::{uninitialized,zeroed}` with certain types results // in a lint. -#![feature(never_type, rustc_attrs)] +#![feature(rustc_attrs)] #![allow(deprecated)] #![deny(invalid_value)] diff --git a/src/test/ui/lint/unused/must_use-unit.rs b/src/test/ui/lint/unused/must_use-unit.rs index 4dd4798abb7ce..8f59bab26d3ef 100644 --- a/src/test/ui/lint/unused/must_use-unit.rs +++ b/src/test/ui/lint/unused/must_use-unit.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![deny(unused_must_use)] #[must_use] diff --git a/src/test/ui/lint/unused/must_use-unit.stderr b/src/test/ui/lint/unused/must_use-unit.stderr index 7f25a19350862..50dbcb0a527fd 100644 --- a/src/test/ui/lint/unused/must_use-unit.stderr +++ b/src/test/ui/lint/unused/must_use-unit.stderr @@ -1,17 +1,17 @@ error: unused return value of `foo` that must be used - --> $DIR/must_use-unit.rs:13:5 + --> $DIR/must_use-unit.rs:12:5 | LL | foo(); | ^^^^^^ | note: the lint level is defined here - --> $DIR/must_use-unit.rs:2:9 + --> $DIR/must_use-unit.rs:1:9 | LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ error: unused return value of `bar` that must be used - --> $DIR/must_use-unit.rs:15:5 + --> $DIR/must_use-unit.rs:14:5 | LL | bar(); | ^^^^^^ diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs index 51c9a36a03956..4102280f33cfc 100644 --- a/src/test/ui/loops/loop-break-value.rs +++ b/src/test/ui/loops/loop-break-value.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - fn main() { let val: ! = loop { break break; }; //~^ ERROR mismatched types diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index ccb27c3507076..ff9a90964a6e6 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `LOOP` in this scope - --> $DIR/loop-break-value.rs:95:15 + --> $DIR/loop-break-value.rs:93:15 | LL | 'LOOP: for _ in 0 .. 9 { | ----- a label with a similar name exists @@ -10,7 +10,7 @@ LL | break LOOP; | help: use the similarly named label: `'LOOP` warning: denote infinite loops with `loop { ... }` - --> $DIR/loop-break-value.rs:26:5 + --> $DIR/loop-break-value.rs:24:5 | LL | 'while_loop: while true { | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop` @@ -18,7 +18,7 @@ LL | 'while_loop: while true { = note: `#[warn(while_true)]` on by default error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:28:9 + --> $DIR/loop-break-value.rs:26:9 | LL | 'while_loop: while true { | ----------------------- you can't `break` with a value in a `while` loop @@ -36,7 +36,7 @@ LL | break 'while_loop; | ~~~~~~~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:30:13 + --> $DIR/loop-break-value.rs:28:13 | LL | 'while_loop: while true { | ----------------------- you can't `break` with a value in a `while` loop @@ -50,7 +50,7 @@ LL | break 'while_loop; | ~~~~~~~~~~~~~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:38:12 + --> $DIR/loop-break-value.rs:36:12 | LL | while let Some(_) = Some(()) { | ---------------------------- you can't `break` with a value in a `while` loop @@ -63,7 +63,7 @@ LL | if break { | ~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:43:9 + --> $DIR/loop-break-value.rs:41:9 | LL | while let Some(_) = Some(()) { | ---------------------------- you can't `break` with a value in a `while` loop @@ -76,7 +76,7 @@ LL | break; | ~~~~~ error[E0571]: `break` with value from a `while` loop - --> $DIR/loop-break-value.rs:49:13 + --> $DIR/loop-break-value.rs:47:13 | LL | 'while_let_loop: while let Some(_) = Some(()) { | --------------------------------------------- you can't `break` with a value in a `while` loop @@ -90,7 +90,7 @@ LL | break 'while_let_loop; | ~~~~~~~~~~~~~~~~~~~~~ error[E0571]: `break` with value from a `for` loop - --> $DIR/loop-break-value.rs:56:9 + --> $DIR/loop-break-value.rs:54:9 | LL | for _ in &[1,2,3] { | ----------------- you can't `break` with a value in a `for` loop @@ -103,7 +103,7 @@ LL | break; | ~~~~~ error[E0571]: `break` with value from a `for` loop - --> $DIR/loop-break-value.rs:57:9 + --> $DIR/loop-break-value.rs:55:9 | LL | for _ in &[1,2,3] { | ----------------- you can't `break` with a value in a `for` loop @@ -117,7 +117,7 @@ LL | break; | ~~~~~ error[E0571]: `break` with value from a `for` loop - --> $DIR/loop-break-value.rs:64:13 + --> $DIR/loop-break-value.rs:62:13 | LL | 'for_loop: for _ in &[1,2,3] { | ---------------------------- you can't `break` with a value in a `for` loop @@ -131,7 +131,7 @@ LL | break 'for_loop; | ~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:4:31 + --> $DIR/loop-break-value.rs:2:31 | LL | let val: ! = loop { break break; }; | ^^^^^ expected `!`, found `()` @@ -140,31 +140,31 @@ LL | let val: ! = loop { break break; }; found unit type `()` error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:11:19 + --> $DIR/loop-break-value.rs:9:19 | LL | break 123; | ^^^ expected `&str`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:16:15 + --> $DIR/loop-break-value.rs:14:15 | LL | break "asdf"; | ^^^^^^ expected `i32`, found `&str` error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:21:31 + --> $DIR/loop-break-value.rs:19:31 | LL | break 'outer_loop "nope"; | ^^^^^^ expected `i32`, found `&str` error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:73:26 + --> $DIR/loop-break-value.rs:71:26 | LL | break 'c 123; | ^^^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:80:15 + --> $DIR/loop-break-value.rs:78:15 | LL | break (break, break); | ^^^^^^^^^^^^^^ expected `()`, found tuple @@ -173,13 +173,13 @@ LL | break (break, break); found tuple `(!, !)` error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:85:15 + --> $DIR/loop-break-value.rs:83:15 | LL | break 2; | ^ expected `()`, found integer error[E0308]: mismatched types - --> $DIR/loop-break-value.rs:90:9 + --> $DIR/loop-break-value.rs:88:9 | LL | break; | ^^^^^ diff --git a/src/test/ui/mir/mir_calls_to_shims.rs b/src/test/ui/mir/mir_calls_to_shims.rs index 6f13d5612ce51..adfdca4c48d3f 100644 --- a/src/test/ui/mir/mir_calls_to_shims.rs +++ b/src/test/ui/mir/mir_calls_to_shims.rs @@ -2,7 +2,7 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] -#![feature(never_type)] + use std::panic; diff --git a/src/test/ui/never_type/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs index 0d7d2c0ed3fa9..3833322d55a74 100644 --- a/src/test/ui/never_type/adjust_never.rs +++ b/src/test/ui/never_type/adjust_never.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + fn main() { let x: ! = panic!(); diff --git a/src/test/ui/never_type/auto-traits.rs b/src/test/ui/never_type/auto-traits.rs index 42ede708e66df..d6c3a13d6ae40 100644 --- a/src/test/ui/never_type/auto-traits.rs +++ b/src/test/ui/never_type/auto-traits.rs @@ -2,7 +2,7 @@ #![feature(auto_traits)] #![feature(negative_impls)] -#![feature(never_type)] + fn main() { enum Void {} diff --git a/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs index d06637e74a2f2..cd3686c95be60 100644 --- a/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs +++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs @@ -1,6 +1,6 @@ // Test that we can't pass other types for ! -#![feature(never_type)] + fn foo(x: !) -> ! { x diff --git a/src/test/ui/never_type/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs index 9d355817ee80d..9ae9962378758 100644 --- a/src/test/ui/never_type/call-fn-never-arg.rs +++ b/src/test/ui/never_type/call-fn-never-arg.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + #![allow(unreachable_code)] fn foo(x: !) -> ! { diff --git a/src/test/ui/never_type/cast-never.rs b/src/test/ui/never_type/cast-never.rs index 0139ebe4640be..db6971e8bec39 100644 --- a/src/test/ui/never_type/cast-never.rs +++ b/src/test/ui/never_type/cast-never.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + fn main() { let x: ! = panic!(); diff --git a/src/test/ui/never_type/defaulted-never-note.rs b/src/test/ui/never_type/defaulted-never-note.rs index 70333c5f324f7..f66c5c1210576 100644 --- a/src/test/ui/never_type/defaulted-never-note.rs +++ b/src/test/ui/never_type/defaulted-never-note.rs @@ -1,6 +1,6 @@ // We need to opt into the `never_type_fallback` feature // to trigger the requirement that this is testing. -#![feature(never_type, never_type_fallback)] +#![feature(never_type_fallback)] #![allow(unused)] diff --git a/src/test/ui/never_type/dispatch_from_dyn_zst.rs b/src/test/ui/never_type/dispatch_from_dyn_zst.rs index 764f58ce9e805..342d5e4791515 100644 --- a/src/test/ui/never_type/dispatch_from_dyn_zst.rs +++ b/src/test/ui/never_type/dispatch_from_dyn_zst.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(unsize, dispatch_from_dyn, never_type)] +#![feature(unsize, dispatch_from_dyn)] #![allow(dead_code)] diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs index f323f40ba31c6..a0a90d6a53b8e 100644 --- a/src/test/ui/never_type/diverging-fallback-control-flow.rs +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -8,7 +8,7 @@ // to fallback based on control-flow. In all of these cases, // the type variable winds up being the target of both a `!` coercion // and a coercion from a non-`!` variable, and hence falls back to `()`. -#![feature(never_type, never_type_fallback)] +// trait UnitDefault { fn default() -> Self; diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.stderr b/src/test/ui/never_type/diverging-fallback-control-flow.stderr new file mode 100644 index 0000000000000..e62aebc9514c2 --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-control-flow.stderr @@ -0,0 +1,10 @@ +warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable + --> $DIR/diverging-fallback-control-flow.rs:11:12 + | +LL | #![feature(never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.stderr index 44566dc6bac7b..08a8f6257912a 100644 --- a/src/test/ui/never_type/diverging-fallback-no-leak.stderr +++ b/src/test/ui/never_type/diverging-fallback-no-leak.stderr @@ -4,7 +4,14 @@ error[E0277]: the trait bound `!: Test` is not satisfied LL | unconstrained_arg(return); | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` | - = note: the trait is implemented for `()`. Possibly this error has been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information). Consider whether you meant to use the type `()` here instead. + = note: this trait is implemented for `()`. + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information). + = help: did you intend to use the type `()` here instead? +note: required by a bound in `unconstrained_arg` + --> $DIR/diverging-fallback-no-leak.rs:7:25 + | +LL | fn unconstrained_arg(_: T) {} + | ^^^^ required by this bound in `unconstrained_arg` error: aborting due to previous error diff --git a/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs index 9a6c965cefb09..2a85062bacfde 100644 --- a/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs +++ b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -6,7 +6,7 @@ // // check-pass -#![feature(never_type_fallback)] + fn make_unit() {} diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.rs b/src/test/ui/never_type/feature-gate-never_type_fallback.rs deleted file mode 100644 index 3b896ec9d70c2..0000000000000 --- a/src/test/ui/never_type/feature-gate-never_type_fallback.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This is a feature gate test for `never_type_fallback`. -// It works by using a scenario where the type fall backs to `()` rather than ´!` -// in the case where `#![feature(never_type_fallback)]` would change it to `!`. - -fn main() {} - -trait T {} - -fn should_ret_unit() -> impl T { - //~^ ERROR the trait bound `(): T` is not satisfied - panic!() -} diff --git a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr b/src/test/ui/never_type/feature-gate-never_type_fallback.stderr deleted file mode 100644 index 670f76867ce45..0000000000000 --- a/src/test/ui/never_type/feature-gate-never_type_fallback.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0277]: the trait bound `(): T` is not satisfied - --> $DIR/feature-gate-never_type_fallback.rs:9:25 - | -LL | fn should_ret_unit() -> impl T { - | ^^^^^^ the trait `T` is not implemented for `()` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs index 9423f08858b9b..fb6d03a6bca27 100644 --- a/src/test/ui/never_type/impl-for-never.rs +++ b/src/test/ui/never_type/impl-for-never.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(never_type)] + // Test that we can call static methods on ! both directly and when it appears in a generic diff --git a/src/test/ui/never_type/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr index b98f6c93923b9..7a05489efd97d 100644 --- a/src/test/ui/never_type/issue-13352.stderr +++ b/src/test/ui/never_type/issue-13352.stderr @@ -1,10 +1,10 @@ -error[E0277]: cannot add `()` to `usize` +error[E0277]: cannot add `!` to `usize` --> $DIR/issue-13352.rs:7:13 | LL | 2_usize + (loop {}); - | ^ no implementation for `usize + ()` + | ^ no implementation for `usize + !` | - = help: the trait `Add<()>` is not implemented for `usize` + = help: the trait `Add` is not implemented for `usize` error: aborting due to previous error diff --git a/src/test/ui/never_type/issue-44402.rs b/src/test/ui/never_type/issue-44402.rs index 699e480dfe7e5..ed21c1cde647a 100644 --- a/src/test/ui/never_type/issue-44402.rs +++ b/src/test/ui/never_type/issue-44402.rs @@ -1,7 +1,7 @@ // check-pass #![allow(dead_code)] -#![feature(never_type)] + #![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old diff --git a/src/test/ui/never_type/issue-51506.rs b/src/test/ui/never_type/issue-51506.rs index d0fe6a0f59a87..acb042fb92be4 100644 --- a/src/test/ui/never_type/issue-51506.rs +++ b/src/test/ui/never_type/issue-51506.rs @@ -1,4 +1,4 @@ -#![feature(never_type, specialization)] +#![feature(specialization)] #![allow(incomplete_features)] use std::iter::{self, Empty}; diff --git a/src/test/ui/never_type/never-assign-dead-code.rs b/src/test/ui/never_type/never-assign-dead-code.rs index 7bb7c87097c50..6082839363cf3 100644 --- a/src/test/ui/never_type/never-assign-dead-code.rs +++ b/src/test/ui/never_type/never-assign-dead-code.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + #![warn(unused)] fn main() { diff --git a/src/test/ui/never_type/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs index 67e26f5663f41..0856fc674db4e 100644 --- a/src/test/ui/never_type/never-assign-wrong-type.rs +++ b/src/test/ui/never_type/never-assign-wrong-type.rs @@ -1,6 +1,6 @@ // Test that we can't use another type in place of ! -#![feature(never_type)] + #![deny(warnings)] fn main() { diff --git a/src/test/ui/never_type/never-associated-type.rs b/src/test/ui/never_type/never-associated-type.rs index 3bb917c931635..e3a269fcee266 100644 --- a/src/test/ui/never_type/never-associated-type.rs +++ b/src/test/ui/never_type/never-associated-type.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + trait Foo { type Wow; diff --git a/src/test/ui/never_type/never-from-impl-is-reserved.rs b/src/test/ui/never_type/never-from-impl-is-reserved.rs index 9d16015bdc129..11d307d17a002 100644 --- a/src/test/ui/never_type/never-from-impl-is-reserved.rs +++ b/src/test/ui/never_type/never-from-impl-is-reserved.rs @@ -1,6 +1,6 @@ // check that the `for T: From` impl is reserved -#![feature(never_type)] + pub struct MyFoo; pub trait MyTrait {} diff --git a/src/test/ui/never_type/never-result.rs b/src/test/ui/never_type/never-result.rs index 35af37910ef3e..0627453c618f8 100644 --- a/src/test/ui/never_type/never-result.rs +++ b/src/test/ui/never_type/never-result.rs @@ -5,7 +5,7 @@ // Test that we can extract a ! through pattern matching then use it as several different types. -#![feature(never_type)] + fn main() { let x: Result = Ok(123); diff --git a/src/test/ui/never_type/never-type-arg.rs b/src/test/ui/never_type/never-type-arg.rs index 13cd59e6aa9f1..7ab1eee1acaff 100644 --- a/src/test/ui/never_type/never-type-arg.rs +++ b/src/test/ui/never_type/never-type-arg.rs @@ -2,7 +2,7 @@ // check-pass -#![feature(never_type)] + struct Wub; diff --git a/src/test/ui/never_type/never-type-rvalues.rs b/src/test/ui/never_type/never-type-rvalues.rs index 9ccc73dbf92d4..78818c347c3aa 100644 --- a/src/test/ui/never_type/never-type-rvalues.rs +++ b/src/test/ui/never_type/never-type-rvalues.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(never_type)] + #![allow(dead_code)] #![allow(path_statements)] #![allow(unreachable_patterns)] diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.rs b/src/test/ui/never_type/never-value-fallback-issue-66757.rs index f2e9e087307db..89444e63c815c 100644 --- a/src/test/ui/never_type/never-value-fallback-issue-66757.rs +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.rs @@ -6,11 +6,6 @@ // // run-pass -#![feature(never_type)] - -// FIXME(#67225) -- this should be true even without the fallback gate. -#![feature(never_type_fallback)] - struct E; impl From for E { diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.stderr b/src/test/ui/never_type/never-value-fallback-issue-66757.stderr new file mode 100644 index 0000000000000..122d1436b16fd --- /dev/null +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.stderr @@ -0,0 +1,10 @@ +warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable + --> $DIR/never-value-fallback-issue-66757.rs:12:12 + | +LL | #![feature(never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/never_type/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs index fce3ced9aac7f..8e1324389d7ab 100644 --- a/src/test/ui/never_type/never_transmute_never.rs +++ b/src/test/ui/never_type/never_transmute_never.rs @@ -2,7 +2,7 @@ #![crate_type="lib"] -#![feature(never_type)] + #![allow(dead_code)] #![allow(unreachable_code)] #![allow(unused_variables)] diff --git a/src/test/ui/never_type/try_from.rs b/src/test/ui/never_type/try_from.rs index 50451576f9c97..2af567a3da947 100644 --- a/src/test/ui/never_type/try_from.rs +++ b/src/test/ui/never_type/try_from.rs @@ -5,7 +5,7 @@ // This test was added to show the motivation for doing this // over `TryFrom` being blanket impl for all `T: From` -#![feature(never_type)] + use std::convert::{TryInto, Infallible}; diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs index 7d1cac8a442f5..56f4f7ea348e3 100644 --- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs @@ -2,7 +2,7 @@ // undecided. This test file currently checks a conservative choice. #![feature(exhaustive_patterns)] -#![feature(never_type)] + #![allow(dead_code)] #![allow(unreachable_code)] diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index b99386e74020e..5b4836a4d74b7 100644 --- a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -1,47 +1,47 @@ error: unreachable pattern - --> $DIR/empty-match.rs:37:9 + --> $DIR/empty-match.rs:36:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/empty-match.rs:8:9 + --> $DIR/empty-match.rs:7:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:40:9 + --> $DIR/empty-match.rs:39:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:47:9 + --> $DIR/empty-match.rs:46:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:50:9 + --> $DIR/empty-match.rs:49:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:57:9 + --> $DIR/empty-match.rs:56:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:60:9 + --> $DIR/empty-match.rs:59:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:78:20 + --> $DIR/empty-match.rs:77:20 | LL | match_no_arms!(0u8); | ^^^ @@ -50,7 +50,7 @@ LL | match_no_arms!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:79:20 + --> $DIR/empty-match.rs:78:20 | LL | struct NonEmptyStruct1; | ----------------------- `NonEmptyStruct1` defined here @@ -62,7 +62,7 @@ LL | match_no_arms!(NonEmptyStruct1); = note: the matched value is of type `NonEmptyStruct1` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:80:20 + --> $DIR/empty-match.rs:79:20 | LL | struct NonEmptyStruct2(bool); | ----------------------------- `NonEmptyStruct2` defined here @@ -74,7 +74,7 @@ LL | match_no_arms!(NonEmptyStruct2(true)); = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:81:20 + --> $DIR/empty-match.rs:80:20 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -88,7 +88,7 @@ LL | match_no_arms!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:82:20 + --> $DIR/empty-match.rs:81:20 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -103,7 +103,7 @@ LL | match_no_arms!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/empty-match.rs:83:20 + --> $DIR/empty-match.rs:82:20 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -118,7 +118,7 @@ LL | match_no_arms!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/empty-match.rs:84:20 + --> $DIR/empty-match.rs:83:20 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -135,7 +135,7 @@ LL | match_no_arms!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/empty-match.rs:85:20 + --> $DIR/empty-match.rs:84:20 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -149,7 +149,7 @@ LL | match_no_arms!(NonEmptyEnum5::V1); = note: the matched value is of type `NonEmptyEnum5` error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:87:24 + --> $DIR/empty-match.rs:86:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -158,7 +158,7 @@ LL | match_guarded_arm!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:88:24 + --> $DIR/empty-match.rs:87:24 | LL | struct NonEmptyStruct1; | ----------------------- `NonEmptyStruct1` defined here @@ -170,7 +170,7 @@ LL | match_guarded_arm!(NonEmptyStruct1); = note: the matched value is of type `NonEmptyStruct1` error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:89:24 + --> $DIR/empty-match.rs:88:24 | LL | struct NonEmptyStruct2(bool); | ----------------------------- `NonEmptyStruct2` defined here @@ -182,7 +182,7 @@ LL | match_guarded_arm!(NonEmptyStruct2(true)); = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:90:24 + --> $DIR/empty-match.rs:89:24 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -196,7 +196,7 @@ LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:91:24 + --> $DIR/empty-match.rs:90:24 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -211,7 +211,7 @@ LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/empty-match.rs:92:24 + --> $DIR/empty-match.rs:91:24 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -226,7 +226,7 @@ LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/empty-match.rs:93:24 + --> $DIR/empty-match.rs:92:24 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -243,7 +243,7 @@ LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/empty-match.rs:94:24 + --> $DIR/empty-match.rs:93:24 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr index b99386e74020e..5b4836a4d74b7 100644 --- a/src/test/ui/pattern/usefulness/empty-match.normal.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr @@ -1,47 +1,47 @@ error: unreachable pattern - --> $DIR/empty-match.rs:37:9 + --> $DIR/empty-match.rs:36:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/empty-match.rs:8:9 + --> $DIR/empty-match.rs:7:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:40:9 + --> $DIR/empty-match.rs:39:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:47:9 + --> $DIR/empty-match.rs:46:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:50:9 + --> $DIR/empty-match.rs:49:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:57:9 + --> $DIR/empty-match.rs:56:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:60:9 + --> $DIR/empty-match.rs:59:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:78:20 + --> $DIR/empty-match.rs:77:20 | LL | match_no_arms!(0u8); | ^^^ @@ -50,7 +50,7 @@ LL | match_no_arms!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:79:20 + --> $DIR/empty-match.rs:78:20 | LL | struct NonEmptyStruct1; | ----------------------- `NonEmptyStruct1` defined here @@ -62,7 +62,7 @@ LL | match_no_arms!(NonEmptyStruct1); = note: the matched value is of type `NonEmptyStruct1` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:80:20 + --> $DIR/empty-match.rs:79:20 | LL | struct NonEmptyStruct2(bool); | ----------------------------- `NonEmptyStruct2` defined here @@ -74,7 +74,7 @@ LL | match_no_arms!(NonEmptyStruct2(true)); = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:81:20 + --> $DIR/empty-match.rs:80:20 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -88,7 +88,7 @@ LL | match_no_arms!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:82:20 + --> $DIR/empty-match.rs:81:20 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -103,7 +103,7 @@ LL | match_no_arms!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/empty-match.rs:83:20 + --> $DIR/empty-match.rs:82:20 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -118,7 +118,7 @@ LL | match_no_arms!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/empty-match.rs:84:20 + --> $DIR/empty-match.rs:83:20 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -135,7 +135,7 @@ LL | match_no_arms!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/empty-match.rs:85:20 + --> $DIR/empty-match.rs:84:20 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -149,7 +149,7 @@ LL | match_no_arms!(NonEmptyEnum5::V1); = note: the matched value is of type `NonEmptyEnum5` error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:87:24 + --> $DIR/empty-match.rs:86:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -158,7 +158,7 @@ LL | match_guarded_arm!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:88:24 + --> $DIR/empty-match.rs:87:24 | LL | struct NonEmptyStruct1; | ----------------------- `NonEmptyStruct1` defined here @@ -170,7 +170,7 @@ LL | match_guarded_arm!(NonEmptyStruct1); = note: the matched value is of type `NonEmptyStruct1` error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:89:24 + --> $DIR/empty-match.rs:88:24 | LL | struct NonEmptyStruct2(bool); | ----------------------------- `NonEmptyStruct2` defined here @@ -182,7 +182,7 @@ LL | match_guarded_arm!(NonEmptyStruct2(true)); = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:90:24 + --> $DIR/empty-match.rs:89:24 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -196,7 +196,7 @@ LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); = note: the matched value is of type `NonEmptyUnion1` error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:91:24 + --> $DIR/empty-match.rs:90:24 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -211,7 +211,7 @@ LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); = note: the matched value is of type `NonEmptyUnion2` error[E0004]: non-exhaustive patterns: `Foo(_)` not covered - --> $DIR/empty-match.rs:92:24 + --> $DIR/empty-match.rs:91:24 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -226,7 +226,7 @@ LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); = note: the matched value is of type `NonEmptyEnum1` error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered - --> $DIR/empty-match.rs:93:24 + --> $DIR/empty-match.rs:92:24 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -243,7 +243,7 @@ LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); = note: the matched value is of type `NonEmptyEnum2` error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered - --> $DIR/empty-match.rs:94:24 + --> $DIR/empty-match.rs:93:24 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs index 8110ec013d7c1..b92d1e8692f63 100644 --- a/src/test/ui/pattern/usefulness/empty-match.rs +++ b/src/test/ui/pattern/usefulness/empty-match.rs @@ -2,7 +2,6 @@ // revisions: normal exhaustive_patterns // // This tests a match with no arms on various types. -#![feature(never_type)] #![feature(never_type_fallback)] #![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] #![deny(unreachable_patterns)] diff --git a/src/test/ui/pattern/usefulness/uninhabited.rs b/src/test/ui/pattern/usefulness/uninhabited.rs index 77cd0f4005e95..dae2f5dcdf220 100644 --- a/src/test/ui/pattern/usefulness/uninhabited.rs +++ b/src/test/ui/pattern/usefulness/uninhabited.rs @@ -3,8 +3,7 @@ // // This tests plays with matching and uninhabited types. This also serves as a test for the // `tcx.is_ty_uninhabited_from()` function. -#![feature(never_type)] -#![feature(never_type_fallback)] +// #![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/ui/pattern/usefulness/uninhabited.stderr b/src/test/ui/pattern/usefulness/uninhabited.stderr new file mode 100644 index 0000000000000..c6c2f5fdeca48 --- /dev/null +++ b/src/test/ui/pattern/usefulness/uninhabited.stderr @@ -0,0 +1,10 @@ +warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable + --> $DIR/uninhabited.rs:6:12 + | +LL | #![feature(never_type_fallback)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index c234547bd14b1..5031e1decab0f 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -4,7 +4,7 @@ // ^-- needed because `--pass check` does not emit the output needed. // FIXME: consider using an attribute instead of side-effects. -#![feature(never_type)] + #![feature(start)] #[start] diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index b45e5daf42c8d..640c2a2cf8fcc 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr index 692bd20f50940..90b5488c81a0e 100644 --- a/src/test/ui/reachable/expr_add.stderr +++ b/src/test/ui/reachable/expr_add.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_add.rs:17:13 + --> $DIR/expr_add.rs:16:13 | LL | let x = Foo + return; | ^^^^^^------ @@ -8,7 +8,7 @@ LL | let x = Foo + return; | unreachable expression | note: the lint level is defined here - --> $DIR/expr_add.rs:3:9 + --> $DIR/expr_add.rs:2:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index e547f75e2697b..3914fb32432ef 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr index c51156b3f40cf..2b05cb2a2966c 100644 --- a/src/test/ui/reachable/expr_assign.stderr +++ b/src/test/ui/reachable/expr_assign.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_assign.rs:10:5 + --> $DIR/expr_assign.rs:9:5 | LL | x = return; | ^^^^------ @@ -8,13 +8,13 @@ LL | x = return; | unreachable expression | note: the lint level is defined here - --> $DIR/expr_assign.rs:5:9 + --> $DIR/expr_assign.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:20:14 + --> $DIR/expr_assign.rs:19:14 | LL | *p = return; | -- ^^^^^^ unreachable expression @@ -22,7 +22,7 @@ LL | *p = return; | any code following this expression is unreachable error: unreachable expression - --> $DIR/expr_assign.rs:26:15 + --> $DIR/expr_assign.rs:25:15 | LL | *{return; &mut i} = 22; | ------ ^^^^^^ unreachable expression diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 1eaa96c3ce773..ce1a94e3c4a25 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr index a5ad9a329f06e..2d7675bbadc40 100644 --- a/src/test/ui/reachable/expr_call.stderr +++ b/src/test/ui/reachable/expr_call.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_call.rs:13:17 + --> $DIR/expr_call.rs:12:17 | LL | foo(return, 22); | ------ ^^ unreachable expression @@ -7,13 +7,13 @@ LL | foo(return, 22); | any code following this expression is unreachable | note: the lint level is defined here - --> $DIR/expr_call.rs:5:9 + --> $DIR/expr_call.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable call - --> $DIR/expr_call.rs:18:5 + --> $DIR/expr_call.rs:17:5 | LL | bar(return); | ^^^ ------ any code following this expression is unreachable diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs index f53bcb97e6972..76a7306b9d9e0 100644 --- a/src/test/ui/reachable/expr_cast.rs +++ b/src/test/ui/reachable/expr_cast.rs @@ -2,7 +2,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type, type_ascription)] +#![feature(type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index d917df05b3c3d..e74a7daec8828 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr index 41c3b8a39060f..1bf797ec06307 100644 --- a/src/test/ui/reachable/expr_method.stderr +++ b/src/test/ui/reachable/expr_method.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_method.rs:16:21 + --> $DIR/expr_method.rs:15:21 | LL | Foo.foo(return, 22); | ------ ^^ unreachable expression @@ -7,13 +7,13 @@ LL | Foo.foo(return, 22); | any code following this expression is unreachable | note: the lint level is defined here - --> $DIR/expr_method.rs:5:9 + --> $DIR/expr_method.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable call - --> $DIR/expr_method.rs:21:9 + --> $DIR/expr_method.rs:20:9 | LL | Foo.bar(return); | ^^^ ------ any code following this expression is unreachable diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs index 8d32397b54248..ff647bda0e87e 100644 --- a/src/test/ui/reachable/expr_type.rs +++ b/src/test/ui/reachable/expr_type.rs @@ -2,7 +2,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type, type_ascription)] +#![feature(type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index e229d22ebc798..6f221c360cb17 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 063d841c25e39..5186252f945e6 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,11 +1,11 @@ error[E0600]: cannot apply unary operator `!` to type `!` - --> $DIR/expr_unary.rs:8:16 + --> $DIR/expr_unary.rs:7:16 | LL | let x: ! = ! { return; }; | ^^^^^^^^^^^^^ cannot apply unary operator `!` error: unreachable expression - --> $DIR/expr_unary.rs:8:16 + --> $DIR/expr_unary.rs:7:16 | LL | let x: ! = ! { return; }; | ^^^^------^^^ @@ -14,7 +14,7 @@ LL | let x: ! = ! { return; }; | unreachable expression | note: the lint level is defined here - --> $DIR/expr_unary.rs:5:9 + --> $DIR/expr_unary.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/unreachable-loop-patterns.rs b/src/test/ui/reachable/unreachable-loop-patterns.rs index 4de29c3c3d761..c8ff56539116f 100644 --- a/src/test/ui/reachable/unreachable-loop-patterns.rs +++ b/src/test/ui/reachable/unreachable-loop-patterns.rs @@ -1,4 +1,4 @@ -#![feature(never_type, never_type_fallback)] +#![feature(never_type_fallback)] #![feature(exhaustive_patterns)] #![allow(unreachable_code)] diff --git a/src/test/ui/reachable/unreachable-try-pattern.rs b/src/test/ui/reachable/unreachable-try-pattern.rs index 23360e73f4a3a..e2d89e93a2aa0 100644 --- a/src/test/ui/reachable/unreachable-try-pattern.rs +++ b/src/test/ui/reachable/unreachable-try-pattern.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(never_type, exhaustive_patterns)] +#![feature(exhaustive_patterns)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/ui/reachable/unwarned-match-on-never.rs b/src/test/ui/reachable/unwarned-match-on-never.rs index 71f8fe3a783e2..639d60ae0ebf8 100644 --- a/src/test/ui/reachable/unwarned-match-on-never.rs +++ b/src/test/ui/reachable/unwarned-match-on-never.rs @@ -1,7 +1,7 @@ #![deny(unreachable_code)] #![allow(dead_code)] -#![feature(never_type)] + fn foo(x: !) -> bool { // Explicit matches on the never type are unwarned. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs index a2735d4cbfb29..30918aa6bba3c 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -1,5 +1,5 @@ #![crate_type = "rlib"] -#![feature(never_type)] + #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs index 80b9dc4c1c338..586d26ac9a23f 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs @@ -1,5 +1,5 @@ // aux-build:uninhabited.rs -#![feature(never_type)] + extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs index 6b911dd989cc5..c3c0ce650d73e 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - #[non_exhaustive] pub enum UninhabitedEnum { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr index fd2c56974bd4a..16a62a992497d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:30:5 + --> $DIR/coercions_same_crate.rs:28:5 | LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { | - expected `A` because of return type @@ -7,7 +7,7 @@ LL | x | ^ expected struct `A`, found enum `UninhabitedEnum` error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:34:5 + --> $DIR/coercions_same_crate.rs:32:5 | LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { | - expected `A` because of return type @@ -15,7 +15,7 @@ LL | x | ^ expected struct `A`, found struct `UninhabitedTupleStruct` error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:38:5 + --> $DIR/coercions_same_crate.rs:36:5 | LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { | - expected `A` because of return type @@ -23,7 +23,7 @@ LL | x | ^ expected struct `A`, found struct `UninhabitedStruct` error[E0308]: mismatched types - --> $DIR/coercions_same_crate.rs:42:5 + --> $DIR/coercions_same_crate.rs:40:5 | LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { | - expected `A` because of return type diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs index 98a7fdbc5049a..3a2c3ca93fa0c 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs @@ -1,5 +1,5 @@ // aux-build:uninhabited.rs -#![feature(never_type)] + extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs index 8f090fe886a00..9c3ec4240a5fd 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - #[non_exhaustive] pub enum UninhabitedEnum { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr index 42bf67c0a45df..b076dcb54d8f2 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty - --> $DIR/indirect_match_same_crate.rs:34:11 + --> $DIR/indirect_match_same_crate.rs:32:11 | LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here @@ -11,7 +11,7 @@ LL | match x {} = note: the matched value is of type `IndirectUninhabitedEnum` error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty - --> $DIR/indirect_match_same_crate.rs:38:11 + --> $DIR/indirect_match_same_crate.rs:36:11 | LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here @@ -23,7 +23,7 @@ LL | match x {} = note: the matched value is of type `IndirectUninhabitedStruct` error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty - --> $DIR/indirect_match_same_crate.rs:42:11 + --> $DIR/indirect_match_same_crate.rs:40:11 | LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here @@ -35,7 +35,7 @@ LL | match x {} = note: the matched value is of type `IndirectUninhabitedTupleStruct` error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty - --> $DIR/indirect_match_same_crate.rs:48:11 + --> $DIR/indirect_match_same_crate.rs:46:11 | LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs index be86519ecb159..ceee3033aa5f8 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs @@ -1,7 +1,7 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] + extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs index 60289aa780378..bc2c471c2d2cf 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -2,7 +2,7 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] + #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs index 230ac75298e72..5840012fe2eaf 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs @@ -1,6 +1,6 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] -#![feature(never_type)] + extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs index e54098d4d48b9..c401af7cbdb07 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -1,5 +1,5 @@ // aux-build:uninhabited.rs -#![feature(never_type)] + extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs index ebbdfba15f3a3..c31688add91b2 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - #[non_exhaustive] pub enum UninhabitedEnum { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr index e4d0c7022f3b4..7c7fad21ba429 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty - --> $DIR/match_same_crate.rs:30:11 + --> $DIR/match_same_crate.rs:28:11 | LL | / pub struct UninhabitedStruct { LL | | _priv: !, @@ -13,7 +13,7 @@ LL | match x {} = note: the matched value is of type `UninhabitedStruct` error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty - --> $DIR/match_same_crate.rs:34:11 + --> $DIR/match_same_crate.rs:32:11 | LL | pub struct UninhabitedTupleStruct(!); | ------------------------------------- `UninhabitedTupleStruct` defined here @@ -25,7 +25,7 @@ LL | match x {} = note: the matched value is of type `UninhabitedTupleStruct` error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered - --> $DIR/match_same_crate.rs:38:11 + --> $DIR/match_same_crate.rs:36:11 | LL | / pub enum UninhabitedVariants { LL | | #[non_exhaustive] Tuple(!), diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs index 900dfff652ea6..212244db9a442 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -1,7 +1,7 @@ // aux-build:uninhabited.rs #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] + extern crate uninhabited; diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs index de5530485f3e6..67296b2759b08 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -2,7 +2,7 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] + #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs index ffc496a975ecf..b0294af0766fe 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -1,6 +1,6 @@ #![deny(unreachable_patterns)] #![feature(exhaustive_patterns)] -#![feature(never_type)] + #[non_exhaustive] pub enum UninhabitedEnum { diff --git a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs index fcc09b159ec23..822237dbb1a93 100644 --- a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs +++ b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.rs @@ -1,6 +1,6 @@ // run-pass -#![allow(irrefutable_let_patterns)] +#![allow(irrefutable_let_patterns, unreachable_patterns)] fn main() { let x: bool; diff --git a/src/test/ui/statics/uninhabited-static.rs b/src/test/ui/statics/uninhabited-static.rs index cc78f6cfa53f7..8b459f26139db 100644 --- a/src/test/ui/statics/uninhabited-static.rs +++ b/src/test/ui/statics/uninhabited-static.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![deny(uninhabited_static)] enum Void {} diff --git a/src/test/ui/statics/uninhabited-static.stderr b/src/test/ui/statics/uninhabited-static.stderr index 5d95b29993827..fe4f86c865bf5 100644 --- a/src/test/ui/statics/uninhabited-static.stderr +++ b/src/test/ui/statics/uninhabited-static.stderr @@ -1,11 +1,11 @@ error: static of uninhabited type - --> $DIR/uninhabited-static.rs:6:5 + --> $DIR/uninhabited-static.rs:5:5 | LL | static VOID: Void; | ^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/uninhabited-static.rs:2:9 + --> $DIR/uninhabited-static.rs:1:9 | LL | #![deny(uninhabited_static)] | ^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | #![deny(uninhabited_static)] = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type - --> $DIR/uninhabited-static.rs:8:5 + --> $DIR/uninhabited-static.rs:7:5 | LL | static NEVER: !; | ^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | static NEVER: !; = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type - --> $DIR/uninhabited-static.rs:12:1 + --> $DIR/uninhabited-static.rs:11:1 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type - --> $DIR/uninhabited-static.rs:14:1 + --> $DIR/uninhabited-static.rs:13:1 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/structs-enums/type-sizes.rs b/src/test/ui/structs-enums/type-sizes.rs index 73a11a5e743f6..a25e407a54474 100644 --- a/src/test/ui/structs-enums/type-sizes.rs +++ b/src/test/ui/structs-enums/type-sizes.rs @@ -2,7 +2,7 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(never_type)] + use std::mem::size_of; use std::num::NonZeroU8; diff --git a/src/test/ui/traits/reservation-impl/non-lattice-ok.rs b/src/test/ui/traits/reservation-impl/non-lattice-ok.rs index a71051243c893..e562b41fd9926 100644 --- a/src/test/ui/traits/reservation-impl/non-lattice-ok.rs +++ b/src/test/ui/traits/reservation-impl/non-lattice-ok.rs @@ -30,7 +30,7 @@ // // [ii]: https://smallcultfollowing.com/babysteps/blog/2016/09/24/intersection-impls/ -#![feature(rustc_attrs, never_type)] +#![feature(rustc_attrs)] trait MyTrait {} diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr index 6274029e4f524..003d3cd862ab6 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:12:1 | LL | fn bar() -> Foo { - | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `!` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 @@ -14,7 +14,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:17:1 | LL | fn boo() -> Foo { - | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `!` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs index 48cd92719b49a..84daa35484f81 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![feature(exhaustive_patterns)] mod foo { diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr index 3cb9955674800..dd952a1b61412 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding: `A(_)` not covered - --> $DIR/uninhabited-irrefutable.rs:27:9 + --> $DIR/uninhabited-irrefutable.rs:26:9 | LL | / enum Foo { LL | | A(foo::SecretlyEmpty), diff --git a/src/test/ui/uninhabited/uninhabited-patterns.rs b/src/test/ui/uninhabited/uninhabited-patterns.rs index 58c726d2185c4..1422bcf4f6098 100644 --- a/src/test/ui/uninhabited/uninhabited-patterns.rs +++ b/src/test/ui/uninhabited/uninhabited-patterns.rs @@ -1,8 +1,8 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(never_type)] #![feature(exhaustive_patterns)] + #![deny(unreachable_patterns)] mod foo { diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 3453c2da2784f..9d24096481359 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -43,11 +43,6 @@ declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]); impl<'tcx> LateLintPass<'tcx> for EmptyEnum { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - // Only suggest the `never_type` if the feature is enabled - if !cx.tcx.features().never_type { - return; - } - if let ItemKind::Enum(..) = item.kind { let ty = cx.tcx.type_of(item.def_id); let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); From be24f7b7f649d0731028ee938f152f21cd0e296a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 29 Nov 2020 15:19:07 -0500 Subject: [PATCH 09/17] WIP: make Infallible an alias for ! --- library/core/src/convert/mod.rs | 65 +-------------------------------- library/core/src/num/error.rs | 8 ---- library/std/src/error.rs | 8 ---- 3 files changed, 1 insertion(+), 80 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 1e512af48051e..669d77a119324 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -34,9 +34,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::fmt; -use crate::hash::{Hash, Hasher}; - mod num; #[unstable(feature = "convert_float_to_int", issue = "67057")] @@ -675,64 +672,4 @@ impl AsMut for str { /// the two `impl`s will start to overlap /// and therefore will be disallowed by the language’s trait coherence rules. #[stable(feature = "convert_infallible", since = "1.34.0")] -#[derive(Copy)] -pub enum Infallible {} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Clone for Infallible { - fn clone(&self) -> Infallible { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl fmt::Debug for Infallible { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl fmt::Display for Infallible { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialEq for Infallible { - fn eq(&self, _: &Infallible) -> bool { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Eq for Infallible {} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialOrd for Infallible { - fn partial_cmp(&self, _other: &Self) -> Option { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Ord for Infallible { - fn cmp(&self, _other: &Self) -> crate::cmp::Ordering { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl From for Infallible { - fn from(x: !) -> Self { - x - } -} - -#[stable(feature = "convert_infallible_hash", since = "1.44.0")] -impl Hash for Infallible { - fn hash(&self, _: &mut H) { - match *self {} - } -} +pub type Infallible = !; diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 5ddd0abcf15d3..d3ac3859b8cd2 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -1,6 +1,5 @@ //! Error types for conversion to integral types. -use crate::convert::Infallible; use crate::fmt; /// The error type returned when a checked integral type conversion fails. @@ -28,13 +27,6 @@ impl fmt::Display for TryFromIntError { } } -#[stable(feature = "try_from", since = "1.34.0")] -impl From for TryFromIntError { - fn from(x: Infallible) -> TryFromIntError { - match x {} - } -} - #[stable(feature = "never_type", since = "1.53.0")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { diff --git a/library/std/src/error.rs b/library/std/src/error.rs index f79321f9c0663..cb04c704b394a 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -17,7 +17,6 @@ mod tests; use core::array; -use core::convert::Infallible; use crate::alloc::{AllocError, LayoutError}; use crate::any::TypeId; @@ -462,13 +461,6 @@ impl Error for string::FromUtf16Error { } } -#[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for Infallible { - fn description(&self) -> &str { - match *self {} - } -} - #[stable(feature = "decode_utf16", since = "1.9.0")] impl Error for char::DecodeUtf16Error { #[allow(deprecated)] From 7531f59bc00b02d11ffe6e71962d095cf3f94c23 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 26 Apr 2021 19:00:55 -0400 Subject: [PATCH 10/17] v2 of fallback algo --- compiler/rustc_typeck/src/check/fallback.rs | 61 +++++++++++++++++-- .../never_type/diverging-fallback-no-leak.rs | 2 - .../ui/never_type/fallback-trait-bound.rs | 18 ++++++ .../different_defining_uses_never_type.stderr | 4 +- 4 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/never_type/fallback-trait-bound.rs diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index c5659bb993358..98b24f1d268e9 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -5,7 +5,9 @@ use rustc_data_structures::{ graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, stable_set::FxHashSet, }; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::traits; +use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback @@ -337,17 +339,68 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // reach a member of N. If so, it falls back to `()`. Else // `!`. let mut diverging_fallback = FxHashMap::default(); - for &diverging_vid in &diverging_vids { + diverging_fallback.reserve(diverging_vids.len()); + 'outer: for &diverging_vid in &diverging_vids { let diverging_ty = self.tcx.mk_ty_var(diverging_vid); let root_vid = self.infcx.root_var(diverging_vid); let can_reach_non_diverging = coercion_graph .depth_first_search(root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); + + for obligation in self.fulfillment_cx.borrow_mut().pending_obligations() { + // We need to check if this obligation is a trait bound like + // `root_vid: Foo`, and then we check: + // + // If `(): Foo` may hold, then fallback to (), + // otherwise continue on. + if let ty::PredicateKind::Trait(predicate, constness) = + obligation.predicate.kind().skip_binder() + { + if predicate.trait_ref.def_id + == self.infcx.tcx.require_lang_item(rustc_hir::LangItem::Sized, None) + { + // Skip sized obligations, those are not usually + // 'intentional', satisfied by both ! and () though. + continue; + } + + // If this trait bound is on the current root_vid... + if self.root_vid(predicate.self_ty()) == Some(root_vid) { + // fixme: copy of mk_trait_obligation_with_new_self_ty + let new_self_ty = self.infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: self + .infcx + .tcx + .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), + ..predicate.trait_ref + }; + + // Then contstruct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + traits::ObligationCause::dummy(), + obligation.param_env, + // FIXME: this drops the binder on the floor that + // previously existed? + trait_ref.with_constness(constness).to_predicate(self.infcx.tcx), + ); + if self.infcx.predicate_may_hold(&o) { + // If we might hold for (), then fallback to (). + debug!("fallback to () as {:?} may hold: {:?}", o, diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + continue 'outer; + } + } + } + } + if can_reach_non_diverging { - debug!("fallback to (): {:?}", diverging_vid); + debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.types.unit); } else { - debug!("fallback to !: {:?}", diverging_vid); + debug!("fallback to ! - all diverging: {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); } } diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.rs b/src/test/ui/never_type/diverging-fallback-no-leak.rs index a3a15f0ed885d..ffcc81e0ff90e 100644 --- a/src/test/ui/never_type/diverging-fallback-no-leak.rs +++ b/src/test/ui/never_type/diverging-fallback-no-leak.rs @@ -1,5 +1,3 @@ -#![feature(never_type_fallback)] - fn make_unit() {} trait Test {} diff --git a/src/test/ui/never_type/fallback-trait-bound.rs b/src/test/ui/never_type/fallback-trait-bound.rs new file mode 100644 index 0000000000000..c2aa47a34216c --- /dev/null +++ b/src/test/ui/never_type/fallback-trait-bound.rs @@ -0,0 +1,18 @@ +// check-pass + +trait Bar { } + +impl Bar for () {} +impl Bar for u32 {} + +fn takes_closure_ret(f: F) + where F: FnOnce() -> R, + R: Bar, +{} + +fn main() { + takes_closure_ret(|| ()); + // This would normally fallback to ! without v2 fallback algorithm, + // and then fail because !: Bar is not satisfied. + takes_closure_ret(|| panic!("test")); +} diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr index 003d3cd862ab6..6274029e4f524 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:12:1 | LL | fn bar() -> Foo { - | ^^^^^^^^^^^^^^^ expected `&'static str`, got `!` + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 @@ -14,7 +14,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:17:1 | LL | fn boo() -> Foo { - | ^^^^^^^^^^^^^^^ expected `&'static str`, got `!` + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 From 26403a27ec671c58a957a5526285b462f23e7bf4 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 5 May 2021 09:30:52 -0400 Subject: [PATCH 11/17] v2 algorithm, with the custom if in output obligations rule --- compiler/rustc_typeck/src/check/fallback.rs | 150 +++++++++++------- .../ui/binding/empty-types-in-patterns.stderr | 10 -- .../migrations/mir_calls_to_shims.fixed | 1 - .../migrations/mir_calls_to_shims.rs | 1 - src/test/ui/mir/mir_calls_to_shims.rs | 1 - .../diverging-fallback-control-flow.stderr | 10 -- .../diverging-fallback-no-leak.stderr | 2 +- src/test/ui/never_type/fallback-future.rs | 22 +++ .../ui/never_type/fallback-trait-bound.rs | 12 +- .../never-value-fallback-issue-66757.stderr | 10 -- .../ui/pattern/usefulness/uninhabited.stderr | 10 -- ..._defining_uses_never_type.full_tait.stderr | 1 + .../different_defining_uses_never_type.stderr | 4 +- 13 files changed, 130 insertions(+), 104 deletions(-) delete mode 100644 src/test/ui/binding/empty-types-in-patterns.stderr delete mode 100644 src/test/ui/never_type/diverging-fallback-control-flow.stderr create mode 100644 src/test/ui/never_type/fallback-future.rs delete mode 100644 src/test/ui/never_type/never-value-fallback-issue-66757.stderr delete mode 100644 src/test/ui/pattern/usefulness/uninhabited.stderr diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 98b24f1d268e9..a186751b389e4 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -6,15 +6,89 @@ use rustc_data_structures::{ stable_set::FxHashSet, }; use rustc_middle::traits; -use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +#[derive(Default, Copy, Clone)] +struct FoundRelationships { + /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` + /// obligation, where: + /// + /// * `Foo` is not `Sized` + /// * `(): Foo` may be satisfied + self_in_trait: bool, + /// This is true if we identified that this Ty (`?T`) is found in a `<_ as + /// _>::AssocType = ?T` + output: bool, +} impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback /// occurs. pub(super) fn type_inference_fallback(&self) -> bool { + debug!( + "type-inference-fallback start obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + + let mut relationships: FxHashMap = FxHashMap::default(); + for obligation in self.fulfillment_cx.borrow_mut().pending_obligations() { + if let ty::PredicateKind::Trait(predicate, constness) = + obligation.predicate.kind().skip_binder() + { + if predicate.trait_ref.def_id + != self.infcx.tcx.require_lang_item(rustc_hir::LangItem::Sized, None) + { + // fixme: copy of mk_trait_obligation_with_new_self_ty + let new_self_ty = self.infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: self + .infcx + .tcx + .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), + ..predicate.trait_ref + }; + + // Then contstruct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + traits::ObligationCause::dummy(), + obligation.param_env, + obligation + .predicate + .kind() + .map_bound(|_| { + ty::PredicateKind::Trait( + ty::TraitPredicate { trait_ref }, + constness, + ) + }) + .to_predicate(self.infcx.tcx), + ); + if self.infcx.predicate_may_hold(&o) { + if let Some(ty) = self.root_vid(predicate.self_ty()) { + relationships.entry(ty).or_default().self_in_trait = true; + } + } + } + } + if let ty::PredicateKind::Projection(predicate) = + obligation.predicate.kind().skip_binder() + { + if let Some(ty) = self.root_vid(predicate.ty) { + relationships.entry(ty).or_default().output = true; + } + } + } + // All type checking constraints were added, try to fallback unsolved variables. self.select_obligations_where_possible(false, |_| {}); + + debug!( + "type-inference-fallback post selection obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + let mut fallback_has_occurred = false; // Check if we have any unsolved varibales. If not, no need for fallback. @@ -23,7 +97,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return; } - let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + let diverging_fallback = + self.calculate_diverging_fallback(&unsolved_variables, &relationships); // We do fallback in two passes, to try to generate // better error messages. @@ -249,6 +324,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn calculate_diverging_fallback( &self, unsolved_variables: &[Ty<'tcx>], + relationships: &FxHashMap, ) -> FxHashMap, Ty<'tcx>> { debug!("calculate_diverging_fallback({:?})", unsolved_variables); @@ -335,68 +411,27 @@ impl<'tcx> FnCtxt<'_, 'tcx> { roots_reachable_from_non_diverging, ); + debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations()); + // For each diverging variable, figure out whether it can // reach a member of N. If so, it falls back to `()`. Else // `!`. let mut diverging_fallback = FxHashMap::default(); diverging_fallback.reserve(diverging_vids.len()); - 'outer: for &diverging_vid in &diverging_vids { + for &diverging_vid in &diverging_vids { let diverging_ty = self.tcx.mk_ty_var(diverging_vid); let root_vid = self.infcx.root_var(diverging_vid); let can_reach_non_diverging = coercion_graph .depth_first_search(root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); - for obligation in self.fulfillment_cx.borrow_mut().pending_obligations() { - // We need to check if this obligation is a trait bound like - // `root_vid: Foo`, and then we check: - // - // If `(): Foo` may hold, then fallback to (), - // otherwise continue on. - if let ty::PredicateKind::Trait(predicate, constness) = - obligation.predicate.kind().skip_binder() - { - if predicate.trait_ref.def_id - == self.infcx.tcx.require_lang_item(rustc_hir::LangItem::Sized, None) - { - // Skip sized obligations, those are not usually - // 'intentional', satisfied by both ! and () though. - continue; - } - - // If this trait bound is on the current root_vid... - if self.root_vid(predicate.self_ty()) == Some(root_vid) { - // fixme: copy of mk_trait_obligation_with_new_self_ty - let new_self_ty = self.infcx.tcx.types.unit; - - let trait_ref = ty::TraitRef { - substs: self - .infcx - .tcx - .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), - ..predicate.trait_ref - }; - - // Then contstruct a new obligation with Self = () added - // to the ParamEnv, and see if it holds. - let o = rustc_infer::traits::Obligation::new( - traits::ObligationCause::dummy(), - obligation.param_env, - // FIXME: this drops the binder on the floor that - // previously existed? - trait_ref.with_constness(constness).to_predicate(self.infcx.tcx), - ); - if self.infcx.predicate_may_hold(&o) { - // If we might hold for (), then fallback to (). - debug!("fallback to () as {:?} may hold: {:?}", o, diverging_vid); - diverging_fallback.insert(diverging_ty, self.tcx.types.unit); - continue 'outer; - } - } - } - } + let relationship = relationships.get(&root_vid).copied().unwrap_or_default(); - if can_reach_non_diverging { + if relationship.self_in_trait && relationship.output { + debug!("fallback to () - found trait and projection: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else if can_reach_non_diverging { debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.types.unit); } else { @@ -425,6 +460,15 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let a_vid = self.root_vid(a)?; let b_vid = self.root_vid(b)?; Some((a_vid, b_vid)) + } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: _, + a, + b, + }) = atom + { + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid, b_vid)) } else { None } @@ -436,7 +480,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } /// If `ty` is an unresolved type variable, returns its root vid. - fn root_vid(&self, ty: Ty<'tcx>) -> Option { + pub fn root_vid(&self, ty: Ty<'tcx>) -> Option { Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) } } diff --git a/src/test/ui/binding/empty-types-in-patterns.stderr b/src/test/ui/binding/empty-types-in-patterns.stderr deleted file mode 100644 index bac952981e3b4..0000000000000 --- a/src/test/ui/binding/empty-types-in-patterns.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable - --> $DIR/empty-types-in-patterns.rs:3:12 - | -LL | #![feature(never_type_fallback)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(stable_features)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed index a5652154682c5..745c107eeab02 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.fixed @@ -4,7 +4,6 @@ //~^ NOTE: the lint level is defined here // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] -#![feature(never_type)] use std::panic; diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs index d9acde073fc3d..41aaf90857eff 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.rs @@ -4,7 +4,6 @@ //~^ NOTE: the lint level is defined here // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] -#![feature(never_type)] use std::panic; diff --git a/src/test/ui/mir/mir_calls_to_shims.rs b/src/test/ui/mir/mir_calls_to_shims.rs index adfdca4c48d3f..df7c45ad1d1c7 100644 --- a/src/test/ui/mir/mir_calls_to_shims.rs +++ b/src/test/ui/mir/mir_calls_to_shims.rs @@ -3,7 +3,6 @@ #![feature(fn_traits)] - use std::panic; fn foo(x: u32, y: u32) -> u32 { x/y } diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.stderr b/src/test/ui/never_type/diverging-fallback-control-flow.stderr deleted file mode 100644 index e62aebc9514c2..0000000000000 --- a/src/test/ui/never_type/diverging-fallback-control-flow.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable - --> $DIR/diverging-fallback-control-flow.rs:11:12 - | -LL | #![feature(never_type_fallback)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(stable_features)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.stderr index 08a8f6257912a..e69ef492e8d4b 100644 --- a/src/test/ui/never_type/diverging-fallback-no-leak.stderr +++ b/src/test/ui/never_type/diverging-fallback-no-leak.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: Test` is not satisfied - --> $DIR/diverging-fallback-no-leak.rs:14:5 + --> $DIR/diverging-fallback-no-leak.rs:12:5 | LL | unconstrained_arg(return); | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` diff --git a/src/test/ui/never_type/fallback-future.rs b/src/test/ui/never_type/fallback-future.rs new file mode 100644 index 0000000000000..86d0cb7985e5b --- /dev/null +++ b/src/test/ui/never_type/fallback-future.rs @@ -0,0 +1,22 @@ +// check-pass +// edition:2018 + +use std::future::Future; + +fn foo() { + let ticker = loopify(async move { loop {} }); + + match ticker { + Ok(v) => v, + Err(()) => return, + }; +} + +fn loopify(_: F) -> Result +where + F: Future, +{ + loop {} +} + +fn main() {} diff --git a/src/test/ui/never_type/fallback-trait-bound.rs b/src/test/ui/never_type/fallback-trait-bound.rs index c2aa47a34216c..30abd12360010 100644 --- a/src/test/ui/never_type/fallback-trait-bound.rs +++ b/src/test/ui/never_type/fallback-trait-bound.rs @@ -1,18 +1,20 @@ // check-pass -trait Bar { } +trait Bar {} impl Bar for () {} impl Bar for u32 {} fn takes_closure_ret(f: F) - where F: FnOnce() -> R, - R: Bar, -{} +where + F: FnOnce() -> R, + R: Bar, +{ +} fn main() { takes_closure_ret(|| ()); // This would normally fallback to ! without v2 fallback algorithm, // and then fail because !: Bar is not satisfied. - takes_closure_ret(|| panic!("test")); + takes_closure_ret(|| panic!()); } diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.stderr b/src/test/ui/never_type/never-value-fallback-issue-66757.stderr deleted file mode 100644 index 122d1436b16fd..0000000000000 --- a/src/test/ui/never_type/never-value-fallback-issue-66757.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable - --> $DIR/never-value-fallback-issue-66757.rs:12:12 - | -LL | #![feature(never_type_fallback)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(stable_features)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/pattern/usefulness/uninhabited.stderr b/src/test/ui/pattern/usefulness/uninhabited.stderr deleted file mode 100644 index c6c2f5fdeca48..0000000000000 --- a/src/test/ui/pattern/usefulness/uninhabited.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable - --> $DIR/uninhabited.rs:6:12 - | -LL | #![feature(never_type_fallback)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(stable_features)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr index e69de29bb2d1d..8b137891791fe 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.full_tait.stderr @@ -0,0 +1 @@ + diff --git a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr index 6274029e4f524..003d3cd862ab6 100644 --- a/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr +++ b/src/test/ui/type-alias-impl-trait/different_defining_uses_never_type.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:12:1 | LL | fn bar() -> Foo { - | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `!` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 @@ -14,7 +14,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/different_defining_uses_never_type.rs:17:1 | LL | fn boo() -> Foo { - | ^^^^^^^^^^^^^^^ expected `&'static str`, got `()` + | ^^^^^^^^^^^^^^^ expected `&'static str`, got `!` | note: previous use here --> $DIR/different_defining_uses_never_type.rs:8:1 From a9903a2b3e8ef7adc7637929bbeaf6861525ea75 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 20 May 2021 10:15:56 -0400 Subject: [PATCH 12/17] Adjust self-type to require equality --- .../ui/coercion/coerce-issue-49593-box-never.stderr | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/test/ui/coercion/coerce-issue-49593-box-never.stderr diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never.stderr deleted file mode 100644 index 91df00ef39fe0..0000000000000 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: the feature `never_type_fallback` has been stable since 1.49.0 and no longer requires an attribute to enable - --> $DIR/coerce-issue-49593-box-never.rs:2:12 - | -LL | #![feature(never_type_fallback)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(stable_features)]` on by default - -warning: 1 warning emitted - From a963d8dd89f8e1552c9430df0600743546a581f8 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 20 May 2021 12:54:09 -0400 Subject: [PATCH 13/17] Rebase tests --- library/core/src/mem/mod.rs | 2 +- library/core/src/result.rs | 4 +-- library/core/tests/lib.rs | 2 +- library/std/src/primitive_docs.rs | 4 +-- src/librustdoc/lib.rs | 2 +- src/test/codegen/enum-debug-niche-2.rs | 2 -- ...ny.main-{closure#0}.generator_resume.0.mir | 6 ++-- ...issue_62289.test.ElaborateDrops.before.mir | 12 +++---- ...ntrinsics.unreachable.LowerIntrinsics.diff | 2 +- ...t_switch.identity.SeparateConstSwitch.diff | 30 ++++++++--------- ...num.process_never.SimplifyLocals.after.mir | 16 +++++----- ...enum.process_void.SimplifyLocals.after.mir | 16 +++++----- .../async-await/try-on-option-in-async.stderr | 6 ++-- .../match/pattern-matching-should-fail.stderr | 16 +++++----- .../migrations/mir_calls_to_shims.stderr | 2 +- src/test/ui/empty/empty-never-array.rs | 2 -- src/test/ui/empty/empty-never-array.stderr | 2 +- src/test/ui/issues/issue-32709.stderr | 2 +- .../usefulness/match-privately-empty.rs | 8 ++--- .../usefulness/match-privately-empty.stderr | 2 +- .../ui/process/process-panic-after-fork.rs | 1 - .../ui/try-block/try-block-bad-type.stderr | 4 +-- src/test/ui/try-trait/bad-interconversion.rs | 2 +- .../ui/try-trait/bad-interconversion.stderr | 32 +++++++++---------- src/test/ui/try-trait/option-to-result.stderr | 10 +++--- .../try-on-option-diagnostics.stderr | 8 ++--- src/test/ui/try-trait/try-on-option.stderr | 8 ++--- .../ui/try-trait/try-operator-on-main.stderr | 2 +- .../clippy/clippy_lints/src/empty_enum.rs | 2 -- src/tools/clippy/tests/ui/empty_enum.rs | 1 - .../clippy/tests/ui/must_use_candidates.fixed | 1 - .../clippy/tests/ui/must_use_candidates.rs | 1 - .../tests/ui/result_map_unit_fn_unfixable.rs | 1 - 33 files changed, 98 insertions(+), 113 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 84fd1a532c1aa..652c4b96efd30 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1036,7 +1036,7 @@ pub const fn discriminant(v: &T) -> Discriminant { /// # Examples /// /// ``` -/// # #![feature(never_type)] +/// # #![cfg_attr(bootstrap, feature(never_type))] /// # #![feature(variant_count)] /// /// use std::mem; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 092e6544342b7..1c513968de981 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1410,7 +1410,7 @@ impl> Result { /// Basic usage: /// /// ``` - /// # #![feature(never_type)] + /// # #![cfg_attr(bootstrap, feature(never_type))] /// # #![feature(unwrap_infallible)] /// /// fn only_good_news() -> Result { @@ -1446,7 +1446,7 @@ impl, E> Result { /// Basic usage: /// /// ``` - /// # #![feature(never_type)] + /// # #![cfg_attr(bootstrap, feature(never_type))] /// # #![feature(unwrap_infallible)] /// /// fn only_bad_news() -> Result { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 13f483f19b770..def97957265aa 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -56,7 +56,7 @@ #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(unwrap_infallible)] #![feature(option_result_unwrap_unchecked)] #![feature(result_into_ok_or_err)] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 922e7adee9ed1..bed810e101c37 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -70,7 +70,7 @@ mod prim_bool {} /// write: /// /// ``` -/// #![feature(never_type)] +/// #![cfg_attr(bootstrap, feature(never_type))] /// # fn foo() -> u32 { /// let x: ! = { /// return 123 @@ -229,7 +229,7 @@ mod prim_bool {} /// for example: /// /// ``` -/// #![feature(never_type)] +/// #![cfg_attr(bootstrap, feature(never_type))] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index de32e31ca872f..db0cc688e6bb0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -10,7 +10,7 @@ #![feature(nll)] #![feature(test)] #![feature(crate_visibility_modifier)] -#![feature(never_type)] +#![cfg_attr(bootstrap, feature(never_type))] #![feature(once_cell)] #![feature(type_ascription)] #![feature(iter_intersperse)] diff --git a/src/test/codegen/enum-debug-niche-2.rs b/src/test/codegen/enum-debug-niche-2.rs index 9c72ad9d248a0..6207078f91ede 100644 --- a/src/test/codegen/enum-debug-niche-2.rs +++ b/src/test/codegen/enum-debug-niche-2.rs @@ -10,8 +10,6 @@ // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}} // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}} -#![feature(never_type)] - #[derive(Copy, Clone)] pub struct Entity { private: std::num::NonZeroU32, diff --git a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 539988cad245e..a2935265295a4 100644 --- a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -10,16 +10,16 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), !> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 - let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + let mut _0: std::ops::GeneratorState<(), !>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 let mut _4: !; // in scope 0 at $DIR/generator-tiny.rs:21:9: 24:10 let mut _5: (); // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 let _6: u8; // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18 let mut _7: (); // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18 let _8: (); // in scope 0 at $DIR/generator-tiny.rs:23:13: 23:21 - let mut _9: (); // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25 + let mut _9: !; // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25 let _10: u8; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 scope 1 { diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index 95efa74289d85..39471ea68de9c 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -4,12 +4,12 @@ fn test() -> Option> { let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 let mut _2: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 let mut _4: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _6: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _6: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _8: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _8: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 @@ -56,13 +56,13 @@ fn test() -> Option> { bb4: { StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _6 = ((_3 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _6 = ((_3 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as FromResidual>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 + _0 = > as FromResidual>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } + // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } } bb5: { diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index a04b79d47d4ce..774cdf296d4d7 100644 --- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -4,7 +4,7 @@ fn unreachable() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:23:25: 23:26 let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:23:27: 25:2 - let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:24:14: 24:45 + let _2: !; // in scope 0 at $DIR/lower_intrinsics.rs:24:14: 24:45 let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:24:14: 24:45 scope 1 { } diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index 69f3bec6fea25..4a06fb27a3588 100644 --- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -1,16 +1,16 @@ - // MIR for `identity` before SeparateConstSwitch + // MIR for `identity` after SeparateConstSwitch - + fn identity(_1: Result) -> Result { debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:28:13: 28:14 let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:28:37: 28:53 let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:9 let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 - let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 - let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 1 { debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:29:9: 29:10 @@ -40,7 +40,7 @@ let _11: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 let mut _12: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 let _13: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 - let mut _14: std::result::Result; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 + let mut _14: std::result::Result; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 let mut _15: i32; // in scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 scope 6 { debug v => _11; // in scope 6 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -49,7 +49,7 @@ debug e => _13; // in scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 } } - + bb0: { StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -60,14 +60,14 @@ - switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 + switchInt(move _10) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 } - + bb1: { - StorageDead(_10); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 - _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 - switchInt(move _5) -> [0_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 - } -- +- - bb2: { StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -79,11 +79,11 @@ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } - + - bb3: { + bb2: { StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 - _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 + _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10 StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:29:9: 29:10 StorageLive(_16); // scope 8 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -103,7 +103,7 @@ StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:30:1: 30:2 return; // scope 0 at $DIR/separate_const_switch.rs:30:2: 30:2 } - + - bb4: { + bb3: { StorageLive(_13); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -114,7 +114,7 @@ ((_14 as Err).0: i32) = move _15; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 discriminant(_14) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 StorageDead(_15); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 - ((_3 as Break).0: std::result::Result) = move _14; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 + ((_3 as Break).0: std::result::Result) = move _14; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 discriminant(_3) = 1; // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 StorageDead(_14); // scope 7 at $DIR/separate_const_switch.rs:29:8: 29:10 StorageDead(_13); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -124,12 +124,12 @@ + _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 } - + - bb5: { + bb4: { unreachable; // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 } - + - bb6: { + bb5: { StorageLive(_11); // scope 5 at $DIR/separate_const_switch.rs:29:8: 29:10 @@ -147,4 +147,4 @@ + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10 } } - + diff --git a/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir index c17fe3bb75757..2e95c0403ed18 100644 --- a/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir +++ b/src/test/mir-opt/uninhabited_enum.process_never.SimplifyLocals.after.mir @@ -1,19 +1,19 @@ // MIR for `process_never` after SimplifyLocals fn process_never(_1: *const !) -> () { - debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:7:22: 7:27 - let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:7:39: 7:39 - let _2: &!; // in scope 0 at $DIR/uninhabited-enum.rs:8:8: 8:14 + debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:5:22: 5:27 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:5:39: 5:39 + let _2: &!; // in scope 0 at $DIR/uninhabited-enum.rs:6:8: 6:14 scope 1 { - debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:8:8: 8:14 + debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:6:8: 6:14 } scope 2 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:8:8: 8:14 - _2 = &(*_1); // scope 2 at $DIR/uninhabited-enum.rs:8:26: 8:33 - StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:9:1: 9:2 - unreachable; // scope 0 at $DIR/uninhabited-enum.rs:7:39: 9:2 + StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:6:8: 6:14 + _2 = &(*_1); // scope 2 at $DIR/uninhabited-enum.rs:6:26: 6:33 + StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:7:1: 7:2 + unreachable; // scope 0 at $DIR/uninhabited-enum.rs:5:39: 7:2 } } diff --git a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir index eeaabb7b9884e..efdb9e304db1f 100644 --- a/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir +++ b/src/test/mir-opt/uninhabited_enum.process_void.SimplifyLocals.after.mir @@ -1,19 +1,19 @@ // MIR for `process_void` after SimplifyLocals fn process_void(_1: *const Void) -> () { - debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:13:21: 13:26 - let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:13:41: 13:41 - let _2: &Void; // in scope 0 at $DIR/uninhabited-enum.rs:14:8: 14:14 + debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:11:21: 11:26 + let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:11:41: 11:41 + let _2: &Void; // in scope 0 at $DIR/uninhabited-enum.rs:12:8: 12:14 scope 1 { - debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:14:8: 14:14 + debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:12:8: 12:14 } scope 2 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:14:8: 14:14 - _2 = &(*_1); // scope 2 at $DIR/uninhabited-enum.rs:14:26: 14:33 - StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:17:1: 17:2 - return; // scope 0 at $DIR/uninhabited-enum.rs:17:2: 17:2 + StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:12:8: 12:14 + _2 = &(*_1); // scope 2 at $DIR/uninhabited-enum.rs:12:26: 12:33 + StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:15:1: 15:2 + return; // scope 0 at $DIR/uninhabited-enum.rs:15:2: 15:2 } } diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index e8bb4aca9a9c9..8796be6b072e4 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -10,7 +10,7 @@ LL | | 22 LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `{integer}` + = help: the trait `FromResidual>` is not implemented for `{integer}` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -29,7 +29,7 @@ LL | | 22_u32 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `u32` + = help: the trait `FromResidual>` is not implemented for `u32` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -48,7 +48,7 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `u32` + = help: the trait `FromResidual>` is not implemented for `u32` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr index 45641ea3de3e0..6fe3122139e2e 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr +++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/pattern-matching-should-fail.rs:70:23 + --> $DIR/pattern-matching-should-fail.rs:68:23 | LL | let c1 = || match x { }; | ^ @@ -8,13 +8,13 @@ LL | let c1 = || match x { }; = note: the matched value is of type `u8` error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/pattern-matching-should-fail.rs:8:23 + --> $DIR/pattern-matching-should-fail.rs:6:23 | LL | let c1 = || match x { }; | ^ use of possibly-uninitialized `x` error[E0381]: borrow of possibly-uninitialized variable: `x` - --> $DIR/pattern-matching-should-fail.rs:15:14 + --> $DIR/pattern-matching-should-fail.rs:13:14 | LL | let c2 = || match x { _ => () }; | ^^ - borrow occurs due to use in closure @@ -22,7 +22,7 @@ LL | let c2 = || match x { _ => () }; | use of possibly-uninitialized `x` error[E0381]: borrow of possibly-uninitialized variable: `variant` - --> $DIR/pattern-matching-should-fail.rs:27:13 + --> $DIR/pattern-matching-should-fail.rs:25:13 | LL | let c = || { | ^^ use of possibly-uninitialized `variant` @@ -31,7 +31,7 @@ LL | match variant { | ------- borrow occurs due to use in closure error[E0381]: borrow of possibly-uninitialized variable: `variant` - --> $DIR/pattern-matching-should-fail.rs:39:13 + --> $DIR/pattern-matching-should-fail.rs:37:13 | LL | let c = || { | ^^ use of possibly-uninitialized `variant` @@ -40,19 +40,19 @@ LL | match variant { | ------- borrow occurs due to use in closure error[E0381]: use of possibly-uninitialized variable: `g` - --> $DIR/pattern-matching-should-fail.rs:55:15 + --> $DIR/pattern-matching-should-fail.rs:53:15 | LL | match g { }; | ^ use of possibly-uninitialized `g` error[E0381]: use of possibly-uninitialized variable: `t` - --> $DIR/pattern-matching-should-fail.rs:58:19 + --> $DIR/pattern-matching-should-fail.rs:56:19 | LL | match t { }; | ^ use of possibly-uninitialized `t` error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/pattern-matching-should-fail.rs:70:23 + --> $DIR/pattern-matching-should-fail.rs:68:23 | LL | let c1 = || match x { }; | ^ use of possibly-uninitialized `x` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 10816b7bc3adf..278d590119155 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure - --> $DIR/mir_calls_to_shims.rs:20:38 + --> $DIR/mir_calls_to_shims.rs:19:38 | LL | let result = panic::catch_unwind(move || { | ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe` diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs index 01b99134a445f..a5024449d91d9 100644 --- a/src/test/ui/empty/empty-never-array.rs +++ b/src/test/ui/empty/empty-never-array.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - enum Helper { T(T, [!; 0]), #[allow(dead_code)] diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index 64d640c0e9dbc..e90523cb9223e 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding: `T(_, _)` not covered - --> $DIR/empty-never-array.rs:10:9 + --> $DIR/empty-never-array.rs:8:9 | LL | / enum Helper { LL | | T(T, [!; 0]), diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index bc7eb0688ee84..f9ff7a8618bd2 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -7,7 +7,7 @@ LL | Err(5)?; | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required because of the requirements on the impl of `FromResidual>` for `Result` + = note: required because of the requirements on the impl of `FromResidual>` for `Result` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.rs b/src/test/ui/pattern/usefulness/match-privately-empty.rs index 315eb03d16564..520df830f0291 100644 --- a/src/test/ui/pattern/usefulness/match-privately-empty.rs +++ b/src/test/ui/pattern/usefulness/match-privately-empty.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![feature(exhaustive_patterns)] mod private { @@ -11,11 +10,8 @@ mod private { fn main() { match private::DATA { - //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered + //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered None => {} - Some(private::Private { - misc: false, - .. - }) => {} + Some(private::Private { misc: false, .. }) => {} } } diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr index 4efb41978a241..e9e233808650e 100644 --- a/src/test/ui/pattern/usefulness/match-privately-empty.stderr +++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered - --> $DIR/match-privately-empty.rs:13:11 + --> $DIR/match-privately-empty.rs:12:11 | LL | match private::DATA { | ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered diff --git a/src/test/ui/process/process-panic-after-fork.rs b/src/test/ui/process/process-panic-after-fork.rs index ad749371beac0..985459189d66a 100644 --- a/src/test/ui/process/process-panic-after-fork.rs +++ b/src/test/ui/process/process-panic-after-fork.rs @@ -9,7 +9,6 @@ #![feature(bench_black_box)] #![feature(rustc_private)] -#![feature(never_type)] #![feature(panic_always_abort)] extern crate libc; diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index fce8dbab4856c..25b9990b78bc9 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -6,8 +6,8 @@ LL | Err("")?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following implementations were found: - > - = note: required because of the requirements on the impl of `FromResidual>` for `Result` + > + = note: required because of the requirements on the impl of `FromResidual>` for `Result` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/test/ui/try-trait/bad-interconversion.rs b/src/test/ui/try-trait/bad-interconversion.rs index 385f5510fb414..3f2aca2977502 100644 --- a/src/test/ui/try-trait/bad-interconversion.rs +++ b/src/test/ui/try-trait/bad-interconversion.rs @@ -9,7 +9,7 @@ fn result_to_result() -> Result { fn option_to_result() -> Result { Some(3)?; - //~^ ERROR the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + //~^ ERROR the `?` operator can only be used on `Result`s in a function that returns `Result` Ok(10) } diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 5cecf9128bb2c..18b9a888d7653 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -10,25 +10,25 @@ LL | Ok(Err(123_i32)?) = help: the following implementations were found: > > - = note: required because of the requirements on the impl of `FromResidual>` for `Result` + = note: required because of the requirements on the impl of `FromResidual>` for `Result` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | LL | fn from_residual(residual: R) -> Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` +error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:11:12 | LL | / fn option_to_result() -> Result { LL | | Some(3)?; - | | ^ use `.ok_or(...)?` to provide an error compatible with `Result` + | | ^ this `?` produces `Option`, which is incompatible with `Result` LL | | LL | | Ok(10) LL | | } | |_- this function returns a `Result` | - = help: the trait `FromResidual>` is not implemented for `Result` + = help: the trait `FromResidual>` is not implemented for `Result` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -40,12 +40,12 @@ error[E0277]: the `?` operator can only be used on `Result`s in a function that | LL | / fn control_flow_to_result() -> Result { LL | | Ok(ControlFlow::Break(123)?) - | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result` + | | ^ this `?` produces `ControlFlow<{integer}, !>`, which is incompatible with `Result` LL | | LL | | } | |_- this function returns a `Result` | - = help: the trait `FromResidual>` is not implemented for `Result` + = help: the trait `FromResidual>` is not implemented for `Result` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -57,12 +57,12 @@ error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in | LL | / fn result_to_option() -> Option { LL | | Some(Err("hello")?) - | | ^ use `.ok()?` if you want to discard the `Result` error information + | | ^ use `.ok()?` if you want to discard the `Result` error information LL | | LL | | } | |_- this function returns an `Option` | - = help: the trait `FromResidual>` is not implemented for `Option` + = help: the trait `FromResidual>` is not implemented for `Option` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -74,12 +74,12 @@ error[E0277]: the `?` operator can only be used on `Option`s in a function that | LL | / fn control_flow_to_option() -> Option { LL | | Some(ControlFlow::Break(123)?) - | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option` + | | ^ this `?` produces `ControlFlow<{integer}, !>`, which is incompatible with `Option` LL | | LL | | } | |_- this function returns an `Option` | - = help: the trait `FromResidual>` is not implemented for `Option` + = help: the trait `FromResidual>` is not implemented for `Option` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -91,12 +91,12 @@ error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function | LL | / fn result_to_control_flow() -> ControlFlow { LL | | ControlFlow::Continue(Err("hello")?) - | | ^ this `?` produces `Result`, which is incompatible with `ControlFlow` + | | ^ this `?` produces `Result`, which is incompatible with `ControlFlow` LL | | LL | | } | |_- this function returns a `ControlFlow` | - = help: the trait `FromResidual>` is not implemented for `ControlFlow` + = help: the trait `FromResidual>` is not implemented for `ControlFlow` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -108,13 +108,13 @@ error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function | LL | / fn option_to_control_flow() -> ControlFlow { LL | | Some(3)?; - | | ^ this `?` produces `Option`, which is incompatible with `ControlFlow` + | | ^ this `?` produces `Option`, which is incompatible with `ControlFlow` LL | | LL | | ControlFlow::Break(10) LL | | } | |_- this function returns a `ControlFlow` | - = help: the trait `FromResidual>` is not implemented for `ControlFlow` + = help: the trait `FromResidual>` is not implemented for `ControlFlow` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -126,13 +126,13 @@ error[E0277]: the `?` operator in a function that returns `ControlFlow` ca | LL | / fn control_flow_to_control_flow() -> ControlFlow { LL | | ControlFlow::Break(4_u8)?; - | | ^ this `?` produces `ControlFlow`, which is incompatible with `ControlFlow` + | | ^ this `?` produces `ControlFlow`, which is incompatible with `ControlFlow` LL | | LL | | ControlFlow::Continue(()) LL | | } | |_- this function returns a `ControlFlow` | - = help: the trait `FromResidual>` is not implemented for `ControlFlow` + = help: the trait `FromResidual>` is not implemented for `ControlFlow` = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr index f89813e729fad..edfbae79bad36 100644 --- a/src/test/ui/try-trait/option-to-result.stderr +++ b/src/test/ui/try-trait/option-to-result.stderr @@ -1,15 +1,15 @@ -error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` +error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/option-to-result.rs:5:6 | LL | / fn test_result() -> Result<(),()> { LL | | let a:Option<()> = Some(()); LL | | a?; - | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` + | | ^ this `?` produces `Option`, which is incompatible with `Result<(), ()>` LL | | Ok(()) LL | | } | |_- this function returns a `Result` | - = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` + = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -22,12 +22,12 @@ error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in LL | / fn test_option() -> Option{ LL | | let a:Result = Ok(5); LL | | a?; - | | ^ use `.ok()?` if you want to discard the `Result` error information + | | ^ use `.ok()?` if you want to discard the `Result` error information LL | | Some(5) LL | | } | |_- this function returns an `Option` | - = help: the trait `FromResidual>` is not implemented for `Option` + = help: the trait `FromResidual>` is not implemented for `Option` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/test/ui/try-trait/try-on-option-diagnostics.stderr b/src/test/ui/try-trait/try-on-option-diagnostics.stderr index bb65aae561f97..358fc02f668a6 100644 --- a/src/test/ui/try-trait/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-trait/try-on-option-diagnostics.stderr @@ -9,7 +9,7 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `u32` + = help: the trait `FromResidual>` is not implemented for `u32` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -28,7 +28,7 @@ LL | | 22 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `{integer}` + = help: the trait `FromResidual>` is not implemented for `{integer}` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -45,7 +45,7 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `()` + = help: the trait `FromResidual>` is not implemented for `()` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -62,7 +62,7 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `()` + = help: the trait `FromResidual>` is not implemented for `()` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr index b522dd5709b29..20f11ae0aa5c4 100644 --- a/src/test/ui/try-trait/try-on-option.stderr +++ b/src/test/ui/try-trait/try-on-option.stderr @@ -1,15 +1,15 @@ -error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` +error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/try-on-option.rs:7:6 | LL | / fn foo() -> Result { LL | | let x: Option = None; LL | | x?; - | | ^ use `.ok_or(...)?` to provide an error compatible with `Result` + | | ^ this `?` produces `Option`, which is incompatible with `Result` LL | | Ok(22) LL | | } | |_- this function returns a `Result` | - = help: the trait `FromResidual>` is not implemented for `Result` + = help: the trait `FromResidual>` is not implemented for `Result` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | @@ -27,7 +27,7 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `u32` + = help: the trait `FromResidual>` is not implemented for `u32` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/test/ui/try-trait/try-operator-on-main.stderr b/src/test/ui/try-trait/try-operator-on-main.stderr index d669124e9f112..048f13c33709a 100644 --- a/src/test/ui/try-trait/try-operator-on-main.stderr +++ b/src/test/ui/try-trait/try-operator-on-main.stderr @@ -11,7 +11,7 @@ LL | | try_trait_generic::<()>(); LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `FromResidual>` is not implemented for `()` + = help: the trait `FromResidual>` is not implemented for `()` note: required by `from_residual` --> $SRC_DIR/core/src/ops/try_trait.rs:LL:COL | diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 9d24096481359..b2d1bc79f3510 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -30,8 +30,6 @@ declare_clippy_lint! { /// /// Good: /// ```rust - /// #![feature(never_type)] - /// /// struct Test(!); /// ``` pub EMPTY_ENUM, diff --git a/src/tools/clippy/tests/ui/empty_enum.rs b/src/tools/clippy/tests/ui/empty_enum.rs index a2e5c13c45282..4ffaca317f470 100644 --- a/src/tools/clippy/tests/ui/empty_enum.rs +++ b/src/tools/clippy/tests/ui/empty_enum.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] #![warn(clippy::empty_enum)] // Enable never type to test empty enum lint -#![feature(never_type)] enum Empty {} fn main() {} diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index 9556f6f82cc63..db4142f19262c 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -1,5 +1,4 @@ // run-rustfix -#![feature(never_type)] #![allow(unused_mut, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs index 3732422017104..99426384fabee 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.rs +++ b/src/tools/clippy/tests/ui/must_use_candidates.rs @@ -1,5 +1,4 @@ // run-rustfix -#![feature(never_type)] #![allow(unused_mut, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs index b197c609d7bfc..c00bd437588c4 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs @@ -1,5 +1,4 @@ #![warn(clippy::result_map_unit_fn)] -#![feature(never_type)] #![allow(unused)] struct HasResult { From 73e925986e771c8c403d076c2a2eeefa6108370b Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 21 May 2021 11:47:32 -0400 Subject: [PATCH 14/17] Remove breakage example --- library/core/src/convert/mod.rs | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 669d77a119324..f8d84f5c77f2c 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -645,31 +645,7 @@ impl AsMut for str { /// } /// ``` /// -/// # Future compatibility -/// -/// This enum has the same role as [the `!` “never” type][never], -/// which is unstable in this version of Rust. -/// When `!` is stabilized, we plan to make `Infallible` a type alias to it: -/// -/// ```ignore (illustrates future std change) -/// pub type Infallible = !; -/// ``` -/// -/// … and eventually deprecate `Infallible`. -/// -/// However there is one case where `!` syntax can be used -/// before `!` is stabilized as a full-fledged type: in the position of a function’s return type. -/// Specifically, it is possible implementations for two different function pointer types: -/// -/// ``` -/// trait MyTrait {} -/// impl MyTrait for fn() -> ! {} -/// impl MyTrait for fn() -> std::convert::Infallible {} -/// ``` -/// -/// With `Infallible` being an enum, this code is valid. -/// However when `Infallible` becomes an alias for the never type, -/// the two `impl`s will start to overlap -/// and therefore will be disallowed by the language’s trait coherence rules. +/// This has the same role as [the `!` “never” type][never], and is in fact an +/// alias to it. Generally speaking, you should prefer the never type. #[stable(feature = "convert_infallible", since = "1.34.0")] pub type Infallible = !; From c4532c049b6a7a4d521255cc47cf5d54b72d3430 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 24 May 2021 16:34:23 -0400 Subject: [PATCH 15/17] clippy --- src/tools/clippy/tests/ui/empty_enum.stderr | 2 +- .../tests/ui/empty_enum_without_never_type.stderr | 11 +++++++++++ .../tests/ui/infallible_destructuring_match.fixed | 2 +- .../tests/ui/infallible_destructuring_match.rs | 2 +- src/tools/clippy/tests/ui/must_use_candidates.stderr | 10 +++++----- .../tests/ui/result_map_unit_fn_unfixable.stderr | 12 ++++++------ 6 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 src/tools/clippy/tests/ui/empty_enum_without_never_type.stderr diff --git a/src/tools/clippy/tests/ui/empty_enum.stderr b/src/tools/clippy/tests/ui/empty_enum.stderr index 7125e5f602b75..466dfbe7cee7a 100644 --- a/src/tools/clippy/tests/ui/empty_enum.stderr +++ b/src/tools/clippy/tests/ui/empty_enum.stderr @@ -1,5 +1,5 @@ error: enum with no variants - --> $DIR/empty_enum.rs:5:1 + --> $DIR/empty_enum.rs:4:1 | LL | enum Empty {} | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/empty_enum_without_never_type.stderr b/src/tools/clippy/tests/ui/empty_enum_without_never_type.stderr new file mode 100644 index 0000000000000..7517ed69d9e1b --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_enum_without_never_type.stderr @@ -0,0 +1,11 @@ +error: enum with no variants + --> $DIR/empty_enum_without_never_type.rs:5:1 + | +LL | enum Empty {} + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::empty-enum` implied by `-D warnings` + = help: consider using the uninhabited type `!` (never type) or a wrapper around it to introduce a type which can't be instantiated + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed index b8e40d995531a..04133d1c1d2db 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![feature(exhaustive_patterns, never_type)] +#![feature(exhaustive_patterns)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs index 106cd438b90e7..d32404dff3385 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs @@ -1,5 +1,5 @@ // run-rustfix -#![feature(exhaustive_patterns, never_type)] +#![feature(exhaustive_patterns)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr index 0fa3849d03bff..2f33f5df5f407 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.stderr +++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr @@ -1,5 +1,5 @@ error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:12:1 + --> $DIR/must_use_candidates.rs:11:1 | LL | pub fn pure(i: u8) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8` @@ -7,25 +7,25 @@ LL | pub fn pure(i: u8) -> u8 { = note: `-D clippy::must-use-candidate` implied by `-D warnings` error: this method could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:17:5 + --> $DIR/must_use_candidates.rs:16:5 | LL | pub fn inherent_pure(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8` error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:48:1 + --> $DIR/must_use_candidates.rs:47:1 | LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool` error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:60:1 + --> $DIR/must_use_candidates.rs:59:1 | LL | pub fn rcd(_x: Rc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc) -> bool` error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:68:1 + --> $DIR/must_use_candidates.rs:67:1 | LL | pub fn arcd(_x: Arc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc) -> bool` diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr index 88e4efdb0f054..125276d10804f 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> $DIR/result_map_unit_fn_unfixable.rs:23:5 + --> $DIR/result_map_unit_fn_unfixable.rs:22:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> $DIR/result_map_unit_fn_unfixable.rs:25:5 + --> $DIR/result_map_unit_fn_unfixable.rs:24:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> $DIR/result_map_unit_fn_unfixable.rs:29:5 + --> $DIR/result_map_unit_fn_unfixable.rs:28:5 | LL | x.field.map(|value| { | _____^ @@ -31,7 +31,7 @@ LL | || }); | error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> $DIR/result_map_unit_fn_unfixable.rs:33:5 + --> $DIR/result_map_unit_fn_unfixable.rs:32:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -39,7 +39,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | help: try this: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` - --> $DIR/result_map_unit_fn_unfixable.rs:37:5 + --> $DIR/result_map_unit_fn_unfixable.rs:36:5 | LL | "12".parse::().map(diverge); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -47,7 +47,7 @@ LL | "12".parse::().map(diverge); | help: try this: `if let Ok(a) = "12".parse::() { diverge(a) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` - --> $DIR/result_map_unit_fn_unfixable.rs:43:5 + --> $DIR/result_map_unit_fn_unfixable.rs:42:5 | LL | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- From 5a8bcf9361ff32fa9f7d789cf46af5c529cb2227 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 4 Jul 2021 15:35:45 -0400 Subject: [PATCH 16/17] Relate type variables during predicate registration This avoids select_obligations_where_possible having an effect, which future proofs the algorithm. --- compiler/rustc_infer/src/traits/engine.rs | 3 + compiler/rustc_middle/src/ty/mod.rs | 13 +++ .../src/traits/chalk_fulfill.rs | 15 +++- .../src/traits/fulfill.rs | 13 +++ .../rustc_trait_selection/src/traits/mod.rs | 1 + .../src/traits/relationships.rs | 89 +++++++++++++++++++ compiler/rustc_typeck/src/check/fallback.rs | 87 ++++-------------- .../ui/never_type/fallback-closure-wrap.rs | 16 ++++ .../never_type/fallback-closure-wrap.stderr | 17 ++++ 9 files changed, 182 insertions(+), 72 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/traits/relationships.rs create mode 100644 src/test/ui/never_type/fallback-closure-wrap.rs create mode 100644 src/test/ui/never_type/fallback-closure-wrap.stderr diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 42333dc29bc7c..a12f7dc759c09 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,5 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; @@ -73,6 +74,8 @@ pub trait TraitEngine<'tcx>: 'tcx { } fn pending_obligations(&self) -> Vec>; + + fn relationships(&mut self) -> &mut FxHashMap; } pub trait TraitEngineExt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8aa27d4ca53e3..88fdcbc49fa87 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2084,3 +2084,16 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> { fmt::Display::fmt(&self.name, fmt) } } + +#[derive(Debug, Default, Copy, Clone)] +pub struct FoundRelationships { + /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` + /// obligation, where: + /// + /// * `Foo` is not `Sized` + /// * `(): Foo` may be satisfied + pub self_in_trait: bool, + /// This is true if we identified that this Ty (`?T`) is found in a `<_ as + /// _>::AssocType = ?T` + pub output: bool, +} diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 7a690af0cc6e5..2071d034c5adf 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -7,16 +7,21 @@ use crate::traits::{ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, PredicateObligation, SelectionError, TraitEngine, }; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_middle::ty::{self, Ty}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, + + relationships: FxHashMap, } impl FulfillmentContext<'tcx> { crate fn new() -> Self { - FulfillmentContext { obligations: FxIndexSet::default() } + FulfillmentContext { + obligations: FxIndexSet::default(), + relationships: FxHashMap::default(), + } } } @@ -39,6 +44,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot()); let obligation = infcx.resolve_vars_if_possible(obligation); + super::relationships::update(self, infcx, &obligation); + self.obligations.insert(obligation); } @@ -149,4 +156,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn pending_obligations(&self) -> Vec> { self.obligations.iter().cloned().collect() } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index f214930c57fe4..59da87bf49515 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,5 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; @@ -53,6 +54,9 @@ pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. predicates: ObligationForest>, + + relationships: FxHashMap, + // Should this fulfillment context register type-lives-for-region // obligations on its parent infcx? In some cases, region // obligations are either already known to hold (normalization) or @@ -97,6 +101,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: false, } @@ -105,6 +110,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: true, } @@ -113,6 +119,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: false, usable_in_snapshot: false, } @@ -210,6 +217,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); + super::relationships::update(self, infcx, &obligation); + self.predicates .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } @@ -265,6 +274,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn pending_obligations(&self) -> Vec> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } struct FulfillProcessor<'a, 'b, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 17a4184c3c9ef..e715ad5dd0c62 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -15,6 +15,7 @@ mod object_safety; mod on_unimplemented; mod project; pub mod query; +pub(crate) mod relationships; mod select; mod specialize; mod structural_match; diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs new file mode 100644 index 0000000000000..0f10ae11eb4ac --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -0,0 +1,89 @@ +use crate::infer::InferCtxt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{ObligationCause, PredicateObligation}; +use rustc_infer::traits::TraitEngine; +use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; + +pub(crate) fn update<'tcx, T>( + engine: &mut T, + infcx: &InferCtxt<'_, 'tcx>, + obligation: &PredicateObligation<'tcx>, +) where + T: TraitEngine<'tcx>, +{ + if let ty::PredicateKind::Trait(predicate) = obligation.predicate.kind().skip_binder() { + if predicate.trait_ref.def_id + != infcx.tcx.require_lang_item(rustc_hir::LangItem::Sized, None) + { + // fixme: copy of mk_trait_obligation_with_new_self_ty + let new_self_ty = infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: infcx.tcx.mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), + ..predicate.trait_ref + }; + + // Then contstruct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + obligation + .predicate + .kind() + .map_bound(|_| { + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: predicate.constness, + }) + }) + .to_predicate(infcx.tcx), + ); + // Don't report overflow errors. Otherwise equivalent to may_hold. + if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) { + if result.may_apply() { + if let Some(ty) = infcx + .shallow_resolve(predicate.self_ty()) + .ty_vid() + .map(|t| infcx.root_var(t)) + { + debug!("relationship: {:?}.self_in_trait = true", ty); + engine.relationships().entry(ty).or_default().self_in_trait = true; + } else { + debug!("relationship: did not find TyVid for self ty..."); + } + } + } + } + } + + if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() { + // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, + // we need to make it into one. + if let Some(vid) = predicate.ty.ty_vid() { + debug!("relationship: {:?}.output = true", vid); + engine.relationships().entry(vid).or_default().output = true; + } else { + // This will have registered a projection obligation that will hit + // the Some(vid) branch above. So we don't need to do anything + // further here. + debug!( + "skipping relationship for obligation {:?} -- would need to normalize", + obligation + ); + if !predicate.projection_ty.has_escaping_bound_vars() { + // FIXME: We really *should* do this even with escaping bound + // vars, but there's not much we can do here. In the worst case + // (if this ends up being important) we just don't register a relationship and then end up falling back to !, + // which is not terrible. + + //engine.normalize_projection_type( + // infcx, + // obligation.param_env, + // predicate.projection_ty, + // obligation.cause.clone(), + //); + } + } + } +} diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index a186751b389e4..bf156ae8cf5d2 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -5,22 +5,8 @@ use rustc_data_structures::{ graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, stable_set::FxHashSet, }; -use rustc_middle::traits; -use rustc_middle::ty::{self, ToPredicate, Ty}; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; - -#[derive(Default, Copy, Clone)] -struct FoundRelationships { - /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` - /// obligation, where: - /// - /// * `Foo` is not `Sized` - /// * `(): Foo` may be satisfied - self_in_trait: bool, - /// This is true if we identified that this Ty (`?T`) is found in a `<_ as - /// _>::AssocType = ?T` - output: bool, -} +use rustc_middle::ty::{self, Ty}; + impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback /// occurs. @@ -30,60 +16,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.fulfillment_cx.borrow_mut().pending_obligations() ); - let mut relationships: FxHashMap = FxHashMap::default(); - for obligation in self.fulfillment_cx.borrow_mut().pending_obligations() { - if let ty::PredicateKind::Trait(predicate, constness) = - obligation.predicate.kind().skip_binder() - { - if predicate.trait_ref.def_id - != self.infcx.tcx.require_lang_item(rustc_hir::LangItem::Sized, None) - { - // fixme: copy of mk_trait_obligation_with_new_self_ty - let new_self_ty = self.infcx.tcx.types.unit; - - let trait_ref = ty::TraitRef { - substs: self - .infcx - .tcx - .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), - ..predicate.trait_ref - }; - - // Then contstruct a new obligation with Self = () added - // to the ParamEnv, and see if it holds. - let o = rustc_infer::traits::Obligation::new( - traits::ObligationCause::dummy(), - obligation.param_env, - obligation - .predicate - .kind() - .map_bound(|_| { - ty::PredicateKind::Trait( - ty::TraitPredicate { trait_ref }, - constness, - ) - }) - .to_predicate(self.infcx.tcx), - ); - if self.infcx.predicate_may_hold(&o) { - if let Some(ty) = self.root_vid(predicate.self_ty()) { - relationships.entry(ty).or_default().self_in_trait = true; - } - } - } - } - if let ty::PredicateKind::Projection(predicate) = - obligation.predicate.kind().skip_binder() - { - if let Some(ty) = self.root_vid(predicate.ty) { - relationships.entry(ty).or_default().output = true; - } - } - } - // All type checking constraints were added, try to fallback unsolved variables. self.select_obligations_where_possible(false, |_| {}); + let relationships = self.fulfillment_cx.borrow_mut().relationships().clone(); + + debug!("relationships: {:#?}", relationships); debug!( "type-inference-fallback post selection obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations() @@ -94,7 +32,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // Check if we have any unsolved varibales. If not, no need for fallback. let unsolved_variables = self.unsolved_variables(); if unsolved_variables.is_empty() { - return; + return false; } let diverging_fallback = @@ -324,7 +262,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn calculate_diverging_fallback( &self, unsolved_variables: &[Ty<'tcx>], - relationships: &FxHashMap, + relationships: &FxHashMap, ) -> FxHashMap, Ty<'tcx>> { debug!("calculate_diverging_fallback({:?})", unsolved_variables); @@ -413,6 +351,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations()); debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("relationships: {:#?}", relationships); // For each diverging variable, figure out whether it can // reach a member of N. If so, it falls back to `()`. Else @@ -426,7 +365,15 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .depth_first_search(root_vid) .any(|n| roots_reachable_from_non_diverging.visited(n)); - let relationship = relationships.get(&root_vid).copied().unwrap_or_default(); + let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; + + for (vid, rel) in relationships.iter() { + //if self.infcx.shallow_resolve(*ty).ty_vid().map(|t| self.infcx.root_var(t)) + if self.infcx.root_var(*vid) == root_vid { + relationship.self_in_trait |= rel.self_in_trait; + relationship.output |= rel.output; + } + } if relationship.self_in_trait && relationship.output { debug!("fallback to () - found trait and projection: {:?}", diverging_vid); diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs new file mode 100644 index 0000000000000..9daf6c01faf80 --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -0,0 +1,16 @@ +use std::marker::PhantomData; + +fn main() { + let error = Closure::wrap(Box::new(move || { + //~^ ERROR type mismatch + panic!("Can't connect to server."); + }) as Box); +} + +struct Closure(PhantomData); + +impl Closure { + fn wrap(data: Box) -> Closure { + todo!() + } +} diff --git a/src/test/ui/never_type/fallback-closure-wrap.stderr b/src/test/ui/never_type/fallback-closure-wrap.stderr new file mode 100644 index 0000000000000..10c2cb6d51ab5 --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-wrap.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:4:40: 7:6] as FnOnce<()>>::Output == ()` + --> $DIR/fallback-closure-wrap.rs:4:31 + | +LL | let error = Closure::wrap(Box::new(move || { + | _______________________________^ +LL | | +LL | | panic!("Can't connect to server."); +LL | | }) as Box); + | |______^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + = note: required for the cast to the object type `dyn FnMut()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. From 40d1e6983e75825a44cf67f5437173bf9ebaa4c9 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 5 Jul 2021 16:02:45 -0400 Subject: [PATCH 17/17] Utilize coercion information to guide never type fallback This doesn't yet fully work -- running coercions seems to be prone to causing errors in the environment, which creates a little noise in some cases. It should be enough to let us re-run crater, though, I think. --- compiler/rustc_typeck/src/check/cast.rs | 4 +- compiler/rustc_typeck/src/check/coercion.rs | 53 ++++++++++------ compiler/rustc_typeck/src/check/fallback.rs | 60 ++++++++++++++++++- src/test/ui/issues/issue-22034.rs | 1 + src/test/ui/issues/issue-22034.stderr | 10 +++- .../ui/never_type/fallback-closure-wrap.rs | 3 +- .../never_type/fallback-closure-wrap.stderr | 17 ------ ...rbitrary-self-types-not-object-safe.stderr | 23 ------- 8 files changed, 105 insertions(+), 66 deletions(-) delete mode 100644 src/test/ui/never_type/fallback-closure-wrap.stderr delete mode 100644 src/test/ui/self/arbitrary-self-types-not-object-safe.stderr diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 14550690e63e0..400bc52e1f29f 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -54,8 +54,8 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error; #[derive(Debug)] pub struct CastCheck<'tcx> { expr: &'tcx hir::Expr<'tcx>, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, + pub(crate) expr_ty: Ty<'tcx>, + pub(crate) cast_ty: Ty<'tcx>, cast_span: Span, span: Span, } diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 5ae9041c7b300..7c9e1233a4a10 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -62,7 +62,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; -struct Coerce<'a, 'tcx> { +pub(crate) struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, @@ -116,7 +116,7 @@ fn success<'tcx>( } impl<'f, 'tcx> Coerce<'f, 'tcx> { - fn new( + pub(crate) fn new( fcx: &'f FnCtxt<'f, 'tcx>, cause: ObligationCause<'tcx>, allow_two_phase: AllowTwoPhase, @@ -146,7 +146,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) } + pub(crate) fn coerce_silent(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + self.coerce_(false, a, b) + } + fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + self.coerce_(true, a, b) + } + + fn coerce_(&self, report_error: bool, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { // First, remove any resolved type variables (at the top level, at least): let a = self.shallow_resolve(a); let b = self.shallow_resolve(b); @@ -174,7 +182,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // NOTE: this is wrapped in a `commit_if_ok` because it creates // a "spurious" type variable, and we don't want to have that // type variable in memory if the coercion fails. - let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b)); + let unsize = self.commit_if_ok(|_| self.coerce_unsized(report_error, a, b)); match unsize { Ok(_) => { debug!("coerce: unsize successful"); @@ -482,7 +490,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] // or &Concrete -> &Trait, etc. - fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { + fn coerce_unsized( + &self, + report_error: bool, + mut source: Ty<'tcx>, + mut target: Ty<'tcx>, + ) -> CoerceResult<'tcx> { debug!("coerce_unsized(source={:?}, target={:?})", source, target); source = self.shallow_resolve(source); @@ -690,13 +703,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error( - obligation.clone(), - &obligation, - &err, - false, - false, - ); + if report_error { + self.report_selection_error( + obligation.clone(), + &obligation, + &err, + false, + false, + ); + } // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. @@ -707,13 +722,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { - feature_err( - &self.tcx.sess.parse_sess, - sym::unsized_tuple_coercion, - self.cause.span, - "unsized tuple coercion is not stable enough for use and is subject to change", - ) - .emit(); + if report_error { + feature_err( + &self.tcx.sess.parse_sess, + sym::unsized_tuple_coercion, + self.cause.span, + "unsized tuple coercion is not stable enough for use and is subject to change", + ) + .emit(); + } } if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting { diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index bf156ae8cf5d2..c7ffb21ba20b8 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -5,7 +5,8 @@ use rustc_data_structures::{ graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, stable_set::FxHashSet, }; -use rustc_middle::ty::{self, Ty}; +use rustc_infer::traits::ObligationCauseCode; +use rustc_middle::ty::{self, adjustment::AllowTwoPhase, Ty, TypeFoldable}; impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback @@ -16,6 +17,48 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.fulfillment_cx.borrow_mut().pending_obligations() ); + let mut cast_vars = Vec::new(); + + // FIXME: This seems to cause extra object safety errors. Not clear why; one would expect the probe and such to eat them. + for cast in self.deferred_cast_checks.borrow().iter() { + let source = cast.expr_ty; + let target = cast.cast_ty; + debug!("attempting coerce {:?} -> {:?}", source, target,); + let source = self.resolve_vars_with_obligations(source); + + let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); + // We don't ever need two-phase here since we throw out the result of the coercion + let coerce = crate::check::coercion::Coerce::new(self, cause, AllowTwoPhase::No); + if let Ok(infok) = self.probe(|_| coerce.coerce_silent(source, target)) { + for obligation in infok.obligations { + if let ty::PredicateKind::Projection(predicate) = + obligation.predicate.kind().skip_binder() + { + if !predicate.projection_ty.has_escaping_bound_vars() { + // FIXME: We really *should* do this even with escaping bound + // vars, but there's not much we can do here. In the worst case + // (if this ends up being important) we just don't register a relationship and then end up falling back to !, + // which is not terrible. + + if let Some(vid) = self + .fulfillment_cx + .borrow_mut() + .normalize_projection_type( + &self.infcx, + obligation.param_env, + predicate.projection_ty, + obligation.cause.clone(), + ) + .ty_vid() + { + cast_vars.push(vid); + } + } + } + } + } + } + // All type checking constraints were added, try to fallback unsolved variables. self.select_obligations_where_possible(false, |_| {}); @@ -36,7 +79,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } let diverging_fallback = - self.calculate_diverging_fallback(&unsolved_variables, &relationships); + self.calculate_diverging_fallback(&unsolved_variables, &relationships, &cast_vars); // We do fallback in two passes, to try to generate // better error messages. @@ -263,6 +306,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { &self, unsolved_variables: &[Ty<'tcx>], relationships: &FxHashMap, + cast_vars: &[ty::TyVid], ) -> FxHashMap, Ty<'tcx>> { debug!("calculate_diverging_fallback({:?})", unsolved_variables); @@ -368,16 +412,26 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; for (vid, rel) in relationships.iter() { - //if self.infcx.shallow_resolve(*ty).ty_vid().map(|t| self.infcx.root_var(t)) if self.infcx.root_var(*vid) == root_vid { relationship.self_in_trait |= rel.self_in_trait; relationship.output |= rel.output; } } + let mut is_cast = false; + for vid in cast_vars.iter() { + if self.infcx.root_var(*vid) == root_vid { + is_cast = true; + break; + } + } + if relationship.self_in_trait && relationship.output { debug!("fallback to () - found trait and projection: {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else if is_cast { + debug!("fallback to () - interacted with cast: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); } else if can_reach_non_diverging { debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.types.unit); diff --git a/src/test/ui/issues/issue-22034.rs b/src/test/ui/issues/issue-22034.rs index 405ffd089c245..c6dedff1eea36 100644 --- a/src/test/ui/issues/issue-22034.rs +++ b/src/test/ui/issues/issue-22034.rs @@ -1,3 +1,4 @@ +//~ ERROR expected a `FnOnce<()>` closure, found `()` #![feature(rustc_private)] extern crate libc; diff --git a/src/test/ui/issues/issue-22034.stderr b/src/test/ui/issues/issue-22034.stderr index edcd21ebd6b9b..93d43d0453376 100644 --- a/src/test/ui/issues/issue-22034.stderr +++ b/src/test/ui/issues/issue-22034.stderr @@ -1,5 +1,11 @@ +error[E0277]: expected a `FnOnce<()>` closure, found `()` + | + = help: the trait `FnOnce<()>` is not implemented for `()` + = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` + = note: required for the cast to the object type `dyn Fn()` + error[E0277]: expected a `Fn<()>` closure, found `()` - --> $DIR/issue-22034.rs:8:16 + --> $DIR/issue-22034.rs:9:16 | LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn<()>` closure, found `()` @@ -8,6 +14,6 @@ LL | &mut *(ptr as *mut dyn Fn()) = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` = note: required for the cast to the object type `dyn Fn()` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs index 9daf6c01faf80..3c6dac83fb990 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.rs +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -1,8 +1,9 @@ +// check-pass + use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { - //~^ ERROR type mismatch panic!("Can't connect to server."); }) as Box); } diff --git a/src/test/ui/never_type/fallback-closure-wrap.stderr b/src/test/ui/never_type/fallback-closure-wrap.stderr deleted file mode 100644 index 10c2cb6d51ab5..0000000000000 --- a/src/test/ui/never_type/fallback-closure-wrap.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:4:40: 7:6] as FnOnce<()>>::Output == ()` - --> $DIR/fallback-closure-wrap.rs:4:31 - | -LL | let error = Closure::wrap(Box::new(move || { - | _______________________________^ -LL | | -LL | | panic!("Can't connect to server."); -LL | | }) as Box); - | |______^ expected `()`, found `!` - | - = note: expected unit type `()` - found type `!` - = note: required for the cast to the object type `dyn FnMut()` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr deleted file mode 100644 index 353da8fd20b22..0000000000000 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/arbitrary-self-types-not-object-safe.rs:29:32 - | -LL | fn foo(self: &Rc) -> usize; - | --- method `foo`'s `self` parameter cannot be dispatched on -... -LL | let x = Rc::new(5usize) as Rc; - | ^^^^^^^^^^^ the trait `Foo` cannot be made into an object - -error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/arbitrary-self-types-not-object-safe.rs:29:13 - | -LL | fn foo(self: &Rc) -> usize; - | --- method `foo`'s `self` parameter cannot be dispatched on -... -LL | let x = Rc::new(5usize) as Rc; - | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object - | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0038`.