Auto merge of #82159 - BoxyUwU:uwu, r=varkor
Use correct param_env in conservative_is_privately_uninhabited cc `@lcnr` r? `@varkor` since this is your FIXME that was removed ^^
This commit is contained in:
commit
1fdadbf13a
@ -1603,4 +1603,14 @@ rustc_queries! {
|
|||||||
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
|
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
|
||||||
desc { "normalizing opaque types in {:?}", key }
|
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 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ fn layout_raw<'tcx>(
|
|||||||
let layout = cx.layout_raw_uncached(ty);
|
let layout = cx.layout_raw_uncached(ty);
|
||||||
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
||||||
if let Ok(layout) = layout {
|
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());
|
assert!(layout.abi.is_uninhabited());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -584,11 +584,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||||||
let size =
|
let size =
|
||||||
element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
|
element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
|
||||||
|
|
||||||
let abi = if count != 0 && ty.conservative_is_privately_uninhabited(tcx) {
|
let abi =
|
||||||
Abi::Uninhabited
|
if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
|
||||||
} else {
|
Abi::Uninhabited
|
||||||
Abi::Aggregate { sized: true }
|
} else {
|
||||||
};
|
Abi::Aggregate { sized: true }
|
||||||
|
};
|
||||||
|
|
||||||
let largest_niche = if count != 0 { element.largest_niche.clone() } else { None };
|
let largest_niche = if count != 0 { element.largest_niche.clone() } else { None };
|
||||||
|
|
||||||
|
@ -1697,53 +1697,6 @@ impl<'tcx> TyS<'tcx> {
|
|||||||
matches!(self.kind(), Never)
|
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]
|
#[inline]
|
||||||
pub fn is_primitive(&self) -> bool {
|
pub fn is_primitive(&self) -> bool {
|
||||||
self.kind().is_primitive()
|
self.kind().is_primitive()
|
||||||
|
@ -1734,7 +1734,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
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);
|
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1007,9 +1007,9 @@ fn insert_panic_block<'tcx>(
|
|||||||
assert_block
|
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.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1320,7 +1320,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||||||
// `storage_liveness` tells us which locals have live storage at suspension points
|
// `storage_liveness` tells us which locals have live storage at suspension points
|
||||||
let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
|
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
|
// Run the transformation which converts Places from Local to generator struct
|
||||||
// accesses for locals in `remap`.
|
// accesses for locals in `remap`.
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
//! This API is completely unstable and subject to change.
|
//! This API is completely unstable and subject to change.
|
||||||
|
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
|
#![feature(half_open_range_patterns)]
|
||||||
|
#![feature(exclusive_range_pattern)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
|
@ -481,6 +481,63 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
|
|||||||
fn_like.asyncness()
|
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) {
|
pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
*providers = ty::query::Providers {
|
*providers = ty::query::Providers {
|
||||||
asyncness,
|
asyncness,
|
||||||
@ -498,6 +555,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
|||||||
instance_def_size_estimate,
|
instance_def_size_estimate,
|
||||||
issue33140_self_ty,
|
issue33140_self_ty,
|
||||||
impl_defaultness,
|
impl_defaultness,
|
||||||
|
conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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: Foo>(T, [(); T::ASSOC])
|
||||||
|
where
|
||||||
|
[(); T::ASSOC]: ;
|
||||||
|
|
||||||
|
impl Foo for u32 {}
|
||||||
|
|
||||||
|
fn foo<T: Foo>()
|
||||||
|
where
|
||||||
|
[(); T::ASSOC]: ,
|
||||||
|
{
|
||||||
|
let _iced: Iced<T> = return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo::<u32>();
|
||||||
|
}
|
@ -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: Foo>(T, [(); T::ASSOC])
|
||||||
|
where
|
||||||
|
[(); T::ASSOC]: ;
|
||||||
|
|
||||||
|
impl Foo for u32 {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _iced: Iced<u32> = return;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user