From 42cbfd63460a752ec5e57e88a180d7e3268521a9 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 23 Feb 2021 23:35:48 +0000 Subject: [PATCH] yeet --- compiler/rustc_middle/src/query/mod.rs | 10 ++++ compiler/rustc_middle/src/ty/layout.rs | 13 +++-- compiler/rustc_middle/src/ty/sty.rs | 47 --------------- .../src/borrow_check/type_check/mod.rs | 5 +- compiler/rustc_mir/src/transform/generator.rs | 6 +- compiler/rustc_ty_utils/src/lib.rs | 2 + compiler/rustc_ty_utils/src/ty.rs | 58 +++++++++++++++++++ ...ly_uninhabited_uses_correct_param_env-1.rs | 27 +++++++++ ...ly_uninhabited_uses_correct_param_env-2.rs | 20 +++++++ 9 files changed, 131 insertions(+), 57 deletions(-) create mode 100644 src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs create mode 100644 src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f0166ec2167..92b5de01b99 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1632,4 +1632,14 @@ rustc_queries! { query normalize_opaque_types(key: &'tcx ty::List>) -> &'tcx ty::List> { 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 } + } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0b592ca4710..65420bdf9a9 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -231,7 +231,7 @@ fn layout_raw<'tcx>( let layout = cx.layout_raw_uncached(ty); // Type-level uninhabitedness should always imply ABI uninhabitedness. if let Ok(layout) = layout { - if ty.conservative_is_privately_uninhabited(tcx) { + if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) { assert!(layout.abi.is_uninhabited()); } } @@ -583,11 +583,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?; - let abi = if count != 0 && ty.conservative_is_privately_uninhabited(tcx) { - Abi::Uninhabited - } else { - Abi::Aggregate { sized: true } - }; + let abi = + if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) { + Abi::Uninhabited + } else { + Abi::Aggregate { sized: true } + }; let largest_niche = if count != 0 { element.largest_niche.clone() } else { None }; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 04cc4db0bcf..3a66af90cd4 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1685,53 +1685,6 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Never) } - /// 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.) - pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool { - // FIXME(varkor): we can make this less conversative by substituting concrete - // type arguments. - match self.kind() { - ty::Never => true, - ty::Adt(def, _) if def.is_union() => { - // For now, `union`s are never considered uninhabited. - false - } - ty::Adt(def, _) => { - // 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| { - tcx.type_of(field.did).conservative_is_privately_uninhabited(tcx) - }) - }) - } - ty::Tuple(..) => { - self.tuple_fields().any(|ty| ty.conservative_is_privately_uninhabited(tcx)) - } - ty::Array(ty, len) => { - match len.try_eval_usize(tcx, ParamEnv::empty()) { - Some(0) | None => false, - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(1..) => ty.conservative_is_privately_uninhabited(tcx), - } - } - 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 - } - _ => false, - } - } - #[inline] pub fn is_primitive(&self) -> bool { self.kind().is_primitive() diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 52b1ff3877d..a0b18a89974 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1730,7 +1730,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } None => { - if !sig.output().conservative_is_privately_uninhabited(self.tcx()) { + if !self + .tcx() + .conservative_is_privately_uninhabited(self.param_env.and(sig.output())) + { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index dc413f8dd2d..9f996e84528 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -1007,9 +1007,9 @@ fn insert_panic_block<'tcx>( assert_block } -fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { +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 body.return_ty().conservative_is_privately_uninhabited(tcx) { + if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) { return false; } @@ -1320,7 +1320,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // `storage_liveness` tells us which locals have live storage at suspension points let (remap, layout, storage_liveness) = compute_layout(liveness_info, body); - let can_return = can_return(tcx, body); + let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id())); // Run the transformation which converts Places from Local to generator struct // accesses for locals in `remap`. diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 904c0062a92..aa5d3388401 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -5,6 +5,8 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(half_open_range_patterns)] +#![feature(exclusive_range_pattern)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 77aa4413409..940c8ee80fa 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -484,6 +484,63 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { fn_like.asyncness() } +/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. +#[instrument(level = "debug", skip(tcx))] +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.type_of(field.did).subst(tcx, substs); + tcx.conservative_is_privately_uninhabited(param_env.and(ty)) + }) + }) + } + ty::Tuple(..) => { + debug!("ty::Tuple(..) =>"); + ty.tuple_fields().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, @@ -501,6 +558,7 @@ 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/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs new file mode 100644 index 00000000000..d1bffae0d94 --- /dev/null +++ b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs @@ -0,0 +1,27 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause +// ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`. + +trait Foo { + const ASSOC: usize = 1; +} + +struct Iced(T, [(); T::ASSOC]) +where + [(); T::ASSOC]: ; + +impl Foo for u32 {} + +fn foo() +where + [(); T::ASSOC]: , +{ + let _iced: Iced = return; +} + +fn main() { + 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/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs new file mode 100644 index 00000000000..96dbac1fbef --- /dev/null +++ b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs @@ -0,0 +1,20 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause +// ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`. + +trait Foo { + const ASSOC: usize = 1; +} + +struct Iced(T, [(); T::ASSOC]) +where + [(); T::ASSOC]: ; + +impl Foo for u32 {} + +fn main() { + let _iced: Iced = return; +}