Skip to content

Commit 1fdadbf

Browse files
committed
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 ^^
2 parents a8486b6 + 42cbfd6 commit 1fdadbf

File tree

9 files changed

+131
-57
lines changed

9 files changed

+131
-57
lines changed

compiler/rustc_middle/src/query/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1603,4 +1603,14 @@ rustc_queries! {
16031603
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
16041604
desc { "normalizing opaque types in {:?}", key }
16051605
}
1606+
1607+
/// Checks whether a type is definitely uninhabited. This is
1608+
/// conservative: for some types that are uninhabited we return `false`,
1609+
/// but we only return `true` for types that are definitely uninhabited.
1610+
/// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty`
1611+
/// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
1612+
/// size, to account for partial initialisation. See #49298 for details.)
1613+
query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
1614+
desc { "conservatively checking if {:?} is privately uninhabited", key }
1615+
}
16061616
}

compiler/rustc_middle/src/ty/layout.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ fn layout_raw<'tcx>(
232232
let layout = cx.layout_raw_uncached(ty);
233233
// Type-level uninhabitedness should always imply ABI uninhabitedness.
234234
if let Ok(layout) = layout {
235-
if ty.conservative_is_privately_uninhabited(tcx) {
235+
if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
236236
assert!(layout.abi.is_uninhabited());
237237
}
238238
}
@@ -584,11 +584,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
584584
let size =
585585
element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
586586

587-
let abi = if count != 0 && ty.conservative_is_privately_uninhabited(tcx) {
588-
Abi::Uninhabited
589-
} else {
590-
Abi::Aggregate { sized: true }
591-
};
587+
let abi =
588+
if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
589+
Abi::Uninhabited
590+
} else {
591+
Abi::Aggregate { sized: true }
592+
};
592593

593594
let largest_niche = if count != 0 { element.largest_niche.clone() } else { None };
594595

compiler/rustc_middle/src/ty/sty.rs

-47
Original file line numberDiff line numberDiff line change
@@ -1697,53 +1697,6 @@ impl<'tcx> TyS<'tcx> {
16971697
matches!(self.kind(), Never)
16981698
}
16991699

1700-
/// Checks whether a type is definitely uninhabited. This is
1701-
/// conservative: for some types that are uninhabited we return `false`,
1702-
/// but we only return `true` for types that are definitely uninhabited.
1703-
/// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty`
1704-
/// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
1705-
/// size, to account for partial initialisation. See #49298 for details.)
1706-
pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool {
1707-
// FIXME(varkor): we can make this less conversative by substituting concrete
1708-
// type arguments.
1709-
match self.kind() {
1710-
ty::Never => true,
1711-
ty::Adt(def, _) if def.is_union() => {
1712-
// For now, `union`s are never considered uninhabited.
1713-
false
1714-
}
1715-
ty::Adt(def, _) => {
1716-
// Any ADT is uninhabited if either:
1717-
// (a) It has no variants (i.e. an empty `enum`);
1718-
// (b) Each of its variants (a single one in the case of a `struct`) has at least
1719-
// one uninhabited field.
1720-
def.variants.iter().all(|var| {
1721-
var.fields.iter().any(|field| {
1722-
tcx.type_of(field.did).conservative_is_privately_uninhabited(tcx)
1723-
})
1724-
})
1725-
}
1726-
ty::Tuple(..) => {
1727-
self.tuple_fields().any(|ty| ty.conservative_is_privately_uninhabited(tcx))
1728-
}
1729-
ty::Array(ty, len) => {
1730-
match len.try_eval_usize(tcx, ParamEnv::empty()) {
1731-
Some(0) | None => false,
1732-
// If the array is definitely non-empty, it's uninhabited if
1733-
// the type of its elements is uninhabited.
1734-
Some(1..) => ty.conservative_is_privately_uninhabited(tcx),
1735-
}
1736-
}
1737-
ty::Ref(..) => {
1738-
// References to uninitialised memory is valid for any type, including
1739-
// uninhabited types, in unsafe code, so we treat all references as
1740-
// inhabited.
1741-
false
1742-
}
1743-
_ => false,
1744-
}
1745-
}
1746-
17471700
#[inline]
17481701
pub fn is_primitive(&self) -> bool {
17491702
self.kind().is_primitive()

compiler/rustc_mir/src/borrow_check/type_check/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1734,7 +1734,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17341734
}
17351735
}
17361736
None => {
1737-
if !sig.output().conservative_is_privately_uninhabited(self.tcx()) {
1737+
if !self
1738+
.tcx()
1739+
.conservative_is_privately_uninhabited(self.param_env.and(sig.output()))
1740+
{
17381741
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
17391742
}
17401743
}

compiler/rustc_mir/src/transform/generator.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1007,9 +1007,9 @@ fn insert_panic_block<'tcx>(
10071007
assert_block
10081008
}
10091009

1010-
fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
1010+
fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
10111011
// Returning from a function with an uninhabited return type is undefined behavior.
1012-
if body.return_ty().conservative_is_privately_uninhabited(tcx) {
1012+
if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) {
10131013
return false;
10141014
}
10151015

@@ -1320,7 +1320,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
13201320
// `storage_liveness` tells us which locals have live storage at suspension points
13211321
let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
13221322

1323-
let can_return = can_return(tcx, body);
1323+
let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
13241324

13251325
// Run the transformation which converts Places from Local to generator struct
13261326
// accesses for locals in `remap`.

compiler/rustc_ty_utils/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
//! This API is completely unstable and subject to change.
66
77
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
8+
#![feature(half_open_range_patterns)]
9+
#![feature(exclusive_range_pattern)]
810
#![feature(nll)]
911
#![recursion_limit = "256"]
1012

compiler/rustc_ty_utils/src/ty.rs

+58
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,63 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
481481
fn_like.asyncness()
482482
}
483483

484+
/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
485+
#[instrument(level = "debug", skip(tcx))]
486+
pub fn conservative_is_privately_uninhabited_raw<'tcx>(
487+
tcx: TyCtxt<'tcx>,
488+
param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
489+
) -> bool {
490+
let (param_env, ty) = param_env_and.into_parts();
491+
match ty.kind() {
492+
ty::Never => {
493+
debug!("ty::Never =>");
494+
true
495+
}
496+
ty::Adt(def, _) if def.is_union() => {
497+
debug!("ty::Adt(def, _) if def.is_union() =>");
498+
// For now, `union`s are never considered uninhabited.
499+
false
500+
}
501+
ty::Adt(def, substs) => {
502+
debug!("ty::Adt(def, _) if def.is_not_union() =>");
503+
// Any ADT is uninhabited if either:
504+
// (a) It has no variants (i.e. an empty `enum`);
505+
// (b) Each of its variants (a single one in the case of a `struct`) has at least
506+
// one uninhabited field.
507+
def.variants.iter().all(|var| {
508+
var.fields.iter().any(|field| {
509+
let ty = tcx.type_of(field.did).subst(tcx, substs);
510+
tcx.conservative_is_privately_uninhabited(param_env.and(ty))
511+
})
512+
})
513+
}
514+
ty::Tuple(..) => {
515+
debug!("ty::Tuple(..) =>");
516+
ty.tuple_fields().any(|ty| tcx.conservative_is_privately_uninhabited(param_env.and(ty)))
517+
}
518+
ty::Array(ty, len) => {
519+
debug!("ty::Array(ty, len) =>");
520+
match len.try_eval_usize(tcx, param_env) {
521+
Some(0) | None => false,
522+
// If the array is definitely non-empty, it's uninhabited if
523+
// the type of its elements is uninhabited.
524+
Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(ty)),
525+
}
526+
}
527+
ty::Ref(..) => {
528+
debug!("ty::Ref(..) =>");
529+
// References to uninitialised memory is valid for any type, including
530+
// uninhabited types, in unsafe code, so we treat all references as
531+
// inhabited.
532+
false
533+
}
534+
_ => {
535+
debug!("_ =>");
536+
false
537+
}
538+
}
539+
}
540+
484541
pub fn provide(providers: &mut ty::query::Providers) {
485542
*providers = ty::query::Providers {
486543
asyncness,
@@ -498,6 +555,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
498555
instance_def_size_estimate,
499556
issue33140_self_ty,
500557
impl_defaultness,
558+
conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
501559
..*providers
502560
};
503561
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// run-pass
2+
#![feature(const_generics, const_evaluatable_checked)]
3+
#![allow(incomplete_features)]
4+
5+
// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause
6+
// ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`.
7+
8+
trait Foo {
9+
const ASSOC: usize = 1;
10+
}
11+
12+
struct Iced<T: Foo>(T, [(); T::ASSOC])
13+
where
14+
[(); T::ASSOC]: ;
15+
16+
impl Foo for u32 {}
17+
18+
fn foo<T: Foo>()
19+
where
20+
[(); T::ASSOC]: ,
21+
{
22+
let _iced: Iced<T> = return;
23+
}
24+
25+
fn main() {
26+
foo::<u32>();
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-pass
2+
#![feature(const_generics, const_evaluatable_checked)]
3+
#![allow(incomplete_features)]
4+
5+
// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause
6+
// ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`.
7+
8+
trait Foo {
9+
const ASSOC: usize = 1;
10+
}
11+
12+
struct Iced<T: Foo>(T, [(); T::ASSOC])
13+
where
14+
[(); T::ASSOC]: ;
15+
16+
impl Foo for u32 {}
17+
18+
fn main() {
19+
let _iced: Iced<u32> = return;
20+
}

0 commit comments

Comments
 (0)