diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7d36a63943c..9b6c7d27c79 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1564,10 +1564,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } None => { - if !self - .tcx() - .conservative_is_privately_uninhabited(self.param_env.and(sig.output())) - { + if !sig.output().is_privately_uninhabited(self.tcx(), self.param_env) { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 122ad7009cb..a78b294181c 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -217,7 +217,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { let ty = self.tcx.erase_regions(ty); let m = self.tcx.parent_module(expr.hir_id).to_def_id(); let param_env = self.tcx.param_env(m.expect_local()); - if self.tcx.is_ty_uninhabited_from(m, ty, param_env) { + if !ty.is_inhabited_from(self.tcx, m, param_env) { // This function will not return. We model this fact as an infinite loop. self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1); } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 7bbfb70f2c3..bd3589c6c43 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -542,10 +542,10 @@ fn check_must_not_suspend_ty<'tcx>( data: SuspendCheckData<'_, 'tcx>, ) -> bool { if ty.is_unit() - // FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage + // FIXME: should this check `Ty::is_inhabited_from`. This query is not available in this stage // of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in // `must_use` - // || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env) + // || !ty.is_inhabited_from(fcx.tcx, fcx.tcx.parent_module(hir_id).to_def_id(), fcx.param_env) { return false; } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index cdf279313a6..100a8788763 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -201,9 +201,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { plural_len: usize, ) -> bool { if ty.is_unit() - || cx.tcx.is_ty_uninhabited_from( + || !ty.is_inhabited_from( + cx.tcx, cx.tcx.parent_module(expr.hir_id).to_def_id(), - ty, cx.param_env, ) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 02772013437..21097b1fec6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2078,17 +2078,6 @@ rustc_queries! { desc { "normalizing opaque types in `{:?}`", key } } - /// Checks whether a type is definitely uninhabited. This is - /// conservative: for some types that are uninhabited we return `false`, - /// but we only return `true` for types that are definitely uninhabited. - /// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty` - /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero - /// size, to account for partial initialisation. See #49298 for details.) - query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - desc { "conservatively checking if `{}` is privately uninhabited", key.value } - remap_env_constness - } - query limits(key: ()) -> Limits { desc { "looking up limits" } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index b7aa455727d..33f72729798 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -41,6 +41,13 @@ impl<'tcx> InhabitedPredicate<'tcx> { self.apply_inner(tcx, param_env, &|_| Err(())).ok() } + /// Same as `apply`, but `NotInModule(_)` predicates yield `false`. That is, + /// privately uninhabited types are considered always uninhabited. + pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> bool { + let Ok(result) = self.apply_inner::(tcx, param_env, &|_| Ok(true)); + result + } + fn apply_inner( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 786eced61d6..ace81bc4f83 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -29,7 +29,7 @@ //! } //! ``` //! In this code, the type `Foo` will only be visibly uninhabited inside the -//! modules `b`, `c` and `d`. Calling `uninhabited_predicate` on `Foo` will +//! modules `b`, `c` and `d`. Calling `inhabited_predicate` on `Foo` will //! return `NotInModule(b) AND NotInModule(c)`. //! //! We need this information for pattern-matching on `Foo` or types that contain @@ -57,57 +57,6 @@ pub(crate) fn provide(providers: &mut ty::query::Providers) { ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; } -impl<'tcx> TyCtxt<'tcx> { - /// Checks whether a type is visibly uninhabited from a particular module. - /// - /// # Example - /// ``` - /// #![feature(never_type)] - /// # fn main() {} - /// enum Void {} - /// mod a { - /// pub mod b { - /// pub struct SecretlyUninhabited { - /// _priv: !, - /// } - /// } - /// } - /// - /// mod c { - /// use super::Void; - /// pub struct AlsoSecretlyUninhabited { - /// _priv: Void, - /// } - /// mod d { - /// } - /// } - /// - /// struct Foo { - /// x: a::b::SecretlyUninhabited, - /// y: c::AlsoSecretlyUninhabited, - /// } - /// ``` - /// In this code, the type `Foo` will only be visibly uninhabited inside the - /// modules b, c and d. This effects pattern-matching on `Foo` or types that - /// contain `Foo`. - /// - /// # Example - /// ```ignore (illustrative) - /// let foo_result: Result = ... ; - /// let Ok(t) = foo_result; - /// ``` - /// This code should only compile in modules where the uninhabitedness of Foo is - /// visible. - pub fn is_ty_uninhabited_from( - self, - module: DefId, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - !ty.inhabited_predicate(self).apply(self, param_env, module) - } -} - /// Returns an `InhabitedPredicate` that is generic over type parameters and /// requires calling [`InhabitedPredicate::subst`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { @@ -171,6 +120,64 @@ impl<'tcx> Ty<'tcx> { _ => InhabitedPredicate::True, } } + + /// Checks whether a type is visibly uninhabited from a particular module. + /// + /// # Example + /// ``` + /// #![feature(never_type)] + /// # fn main() {} + /// enum Void {} + /// mod a { + /// pub mod b { + /// pub struct SecretlyUninhabited { + /// _priv: !, + /// } + /// } + /// } + /// + /// mod c { + /// use super::Void; + /// pub struct AlsoSecretlyUninhabited { + /// _priv: Void, + /// } + /// mod d { + /// } + /// } + /// + /// struct Foo { + /// x: a::b::SecretlyUninhabited, + /// y: c::AlsoSecretlyUninhabited, + /// } + /// ``` + /// In this code, the type `Foo` will only be visibly uninhabited inside the + /// modules b, c and d. This effects pattern-matching on `Foo` or types that + /// contain `Foo`. + /// + /// # Example + /// ```ignore (illustrative) + /// let foo_result: Result = ... ; + /// let Ok(t) = foo_result; + /// ``` + /// This code should only compile in modules where the uninhabitedness of Foo is + /// visible. + pub fn is_inhabited_from( + self, + tcx: TyCtxt<'tcx>, + module: DefId, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + self.inhabited_predicate(tcx).apply(tcx, param_env, module) + } + + /// Returns true if the type is uninhabited without regard to visibility + pub fn is_privately_uninhabited( + self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + !self.inhabited_predicate(tcx).apply_ignore_module(tcx, param_env) + } } /// N.B. this query should only be called through `Ty::inhabited_predicate` diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 24ecd0a5399..efb6eba7e57 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -271,15 +271,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // MIR checks and ultimately whether code is accepted or not. We can only // omit the return edge if a return type is visibly uninhabited to a module // that makes the call. - target: if this.tcx.is_ty_uninhabited_from( - this.parent_module, - expr.ty, - this.param_env, - ) { - None - } else { - Some(success) - }, + target: expr + .ty + .is_inhabited_from(this.tcx, this.parent_module, this.param_env) + .then_some(success), from_hir_call, fn_span, }, diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 924d2f555b9..caf27eb39d7 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -264,10 +264,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index || { self.tcx.features().exhaustive_patterns - && v.inhabited_predicate(self.tcx, adt_def) + && !v + .inhabited_predicate(self.tcx, adt_def) .subst(self.tcx, substs) - .apply_any_module(self.tcx, self.param_env) - != Some(true) + .apply_ignore_module(self.tcx, self.param_env) } }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 93a3dd8962a..0df228a0d59 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -818,7 +818,7 @@ fn non_exhaustive_match<'p, 'tcx>( } } if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() { - if cx.tcx.is_ty_uninhabited_from(cx.module, *sub_ty, cx.param_env) { + if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) { err.note("references are always considered inhabited"); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 8dc9976eaea..3e370a05376 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -324,7 +324,7 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> { impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { if self.tcx.features().exhaustive_patterns { - self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) + !ty.is_inhabited_from(self.tcx, self.module, self.param_env) } else { false } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c833de3a8a7..fcd63b6cfa1 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1015,7 +1015,7 @@ fn insert_panic_block<'tcx>( fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { // Returning from a function with an uninhabited return type is undefined behavior. - if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) { + if body.return_ty().is_privately_uninhabited(tcx, param_env) { return false; } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 0100860afb9..58e1fe937a6 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1284,20 +1284,19 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { let ty = self.typeck_results.expr_ty(expr); let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id(); - if self.ir.tcx.is_ty_uninhabited_from(m, ty, self.param_env) { - match self.ir.lnks[succ] { - LiveNodeKind::ExprNode(succ_span, succ_id) => { - self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "expression"); - } - LiveNodeKind::VarDefNode(succ_span, succ_id) => { - self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "definition"); - } - _ => {} - }; - self.exit_ln - } else { - succ + if ty.is_inhabited_from(self.ir.tcx, m, self.param_env) { + return succ; } + match self.ir.lnks[succ] { + LiveNodeKind::ExprNode(succ_span, succ_id) => { + self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "expression"); + } + LiveNodeKind::VarDefNode(succ_span, succ_id) => { + self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "definition"); + } + _ => {} + }; + self.exit_ln } fn warn_about_unreachable( diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index b59be0a0ea7..92e8542795f 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -442,8 +442,7 @@ fn layout_of_uncached<'tcx>( let element = cx.layout_of(element)?; let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; - let abi = if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) - { + let abi = if count != 0 && ty.is_privately_uninhabited(tcx, param_env) { Abi::Uninhabited } else { Abi::Aggregate { sized: true } diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index 100926ad446..ee5e7bc2359 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -12,7 +12,7 @@ pub(super) fn sanity_check_layout<'tcx>( layout: &TyAndLayout<'tcx>, ) { // Type-level uninhabitedness should always imply ABI uninhabitedness. - if cx.tcx.conservative_is_privately_uninhabited(cx.param_env.and(layout.ty)) { + if layout.ty.is_privately_uninhabited(cx.tcx, cx.param_env) { assert!(layout.abi.is_uninhabited()); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 99d3bda6ebf..c60ade360df 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -416,62 +416,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness) } -/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. -pub fn conservative_is_privately_uninhabited_raw<'tcx>( - tcx: TyCtxt<'tcx>, - param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> bool { - let (param_env, ty) = param_env_and.into_parts(); - match ty.kind() { - ty::Never => { - debug!("ty::Never =>"); - true - } - ty::Adt(def, _) if def.is_union() => { - debug!("ty::Adt(def, _) if def.is_union() =>"); - // For now, `union`s are never considered uninhabited. - false - } - ty::Adt(def, substs) => { - debug!("ty::Adt(def, _) if def.is_not_union() =>"); - // Any ADT is uninhabited if either: - // (a) It has no variants (i.e. an empty `enum`); - // (b) Each of its variants (a single one in the case of a `struct`) has at least - // one uninhabited field. - def.variants().iter().all(|var| { - var.fields.iter().any(|field| { - let ty = tcx.bound_type_of(field.did).subst(tcx, substs); - tcx.conservative_is_privately_uninhabited(param_env.and(ty)) - }) - }) - } - ty::Tuple(fields) => { - debug!("ty::Tuple(..) =>"); - fields.iter().any(|ty| tcx.conservative_is_privately_uninhabited(param_env.and(ty))) - } - ty::Array(ty, len) => { - debug!("ty::Array(ty, len) =>"); - match len.try_eval_usize(tcx, param_env) { - Some(0) | None => false, - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(*ty)), - } - } - ty::Ref(..) => { - debug!("ty::Ref(..) =>"); - // References to uninitialised memory is valid for any type, including - // uninhabited types, in unsafe code, so we treat all references as - // inhabited. - false - } - _ => { - debug!("_ =>"); - false - } - } -} - pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, @@ -481,7 +425,6 @@ pub fn provide(providers: &mut ty::query::Providers) { instance_def_size_estimate, issue33140_self_ty, impl_defaultness, - conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw, ..*providers }; } diff --git a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs b/src/test/ui/const-generics/inhabited-assoc-ty-ice-1.rs similarity index 84% rename from src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs rename to src/test/ui/const-generics/inhabited-assoc-ty-ice-1.rs index c9e26c302bf..b385406b020 100644 --- a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs +++ b/src/test/ui/const-generics/inhabited-assoc-ty-ice-1.rs @@ -2,7 +2,7 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause +// This tests that the inhabited check doesn't cause // ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`. trait Foo { diff --git a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs b/src/test/ui/const-generics/inhabited-assoc-ty-ice-2.rs similarity index 82% rename from src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs rename to src/test/ui/const-generics/inhabited-assoc-ty-ice-2.rs index 3017920fc98..216d29c7cd4 100644 --- a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs +++ b/src/test/ui/const-generics/inhabited-assoc-ty-ice-2.rs @@ -2,7 +2,7 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause +// This tests that the inhabited check doesn't cause // ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`. trait Foo { diff --git a/src/test/ui/pattern/usefulness/uninhabited.rs b/src/test/ui/pattern/usefulness/uninhabited.rs index 77cd0f4005e..5622808d4c7 100644 --- a/src/test/ui/pattern/usefulness/uninhabited.rs +++ b/src/test/ui/pattern/usefulness/uninhabited.rs @@ -2,7 +2,7 @@ // aux-build:empty.rs // // This tests plays with matching and uninhabited types. This also serves as a test for the -// `tcx.is_ty_uninhabited_from()` function. +// `Ty::is_inhabited_from` function. #![feature(never_type)] #![feature(never_type_fallback)] #![feature(exhaustive_patterns)]