Wrap promoted generator fields in MaybeUninit
This prevents uninhabited fields from "infecting" the abi and largest_niche of the generator layout. This fixes a latent bug, where an uninhabited field could be promoted to the generator prefix and cause the entire generator to become uninhabited.
This commit is contained in:
parent
c43753f910
commit
6fae7f8071
5 changed files with 37 additions and 10 deletions
|
@ -208,6 +208,8 @@ use crate::mem::ManuallyDrop;
|
||||||
/// guarantee may evolve.
|
/// guarantee may evolve.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[stable(feature = "maybe_uninit", since = "1.36.0")]
|
#[stable(feature = "maybe_uninit", since = "1.36.0")]
|
||||||
|
// Lang item so we can wrap other types in it. This is useful for generators.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "maybe_uninit")]
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub union MaybeUninit<T> {
|
pub union MaybeUninit<T> {
|
||||||
|
|
|
@ -365,6 +365,8 @@ language_item_table! {
|
||||||
|
|
||||||
ManuallyDropItem, "manually_drop", manually_drop, Target::Struct;
|
ManuallyDropItem, "manually_drop", manually_drop, Target::Struct;
|
||||||
|
|
||||||
|
MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union;
|
||||||
|
|
||||||
DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait;
|
DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait;
|
||||||
|
|
||||||
// Align offset for stride != 1, must not panic.
|
// Align offset for stride != 1, must not panic.
|
||||||
|
|
|
@ -2347,10 +2347,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.mk_ty(Foreign(def_id))
|
self.mk_ty(Foreign(def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
|
let adt_def = self.adt_def(wrapper_def_id);
|
||||||
let adt_def = self.adt_def(def_id);
|
let substs = InternalSubsts::for_item(self, wrapper_def_id, |param, substs| {
|
||||||
let substs = InternalSubsts::for_item(self, def_id, |param, substs| {
|
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamDefKind::Lifetime |
|
GenericParamDefKind::Lifetime |
|
||||||
GenericParamDefKind::Const => {
|
GenericParamDefKind::Const => {
|
||||||
|
@ -2358,7 +2357,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Type { has_default, .. } => {
|
GenericParamDefKind::Type { has_default, .. } => {
|
||||||
if param.index == 0 {
|
if param.index == 0 {
|
||||||
ty.into()
|
ty_param.into()
|
||||||
} else {
|
} else {
|
||||||
assert!(has_default);
|
assert!(has_default);
|
||||||
self.type_of(param.def_id).subst(self, substs).into()
|
self.type_of(param.def_id).subst(self, substs).into()
|
||||||
|
@ -2369,6 +2368,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.mk_ty(Adt(adt_def, substs))
|
self.mk_ty(Adt(adt_def, substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
|
||||||
|
self.mk_generic_adt(def_id, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem);
|
||||||
|
self.mk_generic_adt(def_id, ty)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
|
pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
|
||||||
self.mk_ty(RawPtr(tm))
|
self.mk_ty(RawPtr(tm))
|
||||||
|
|
|
@ -1406,24 +1406,21 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||||
Abi::Scalar(s) => s.clone(),
|
Abi::Scalar(s) => s.clone(),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
// FIXME(eddyb) wrap each promoted type in `MaybeUninit` so that they
|
|
||||||
// don't poison the `largest_niche` or `abi` fields of `prefix`.
|
|
||||||
let promoted_layouts = ineligible_locals.iter()
|
let promoted_layouts = ineligible_locals.iter()
|
||||||
.map(|local| subst_field(info.field_tys[local]))
|
.map(|local| subst_field(info.field_tys[local]))
|
||||||
|
.map(|ty| tcx.mk_maybe_uninit(ty))
|
||||||
.map(|ty| self.layout_of(ty));
|
.map(|ty| self.layout_of(ty));
|
||||||
let prefix_layouts = substs.prefix_tys(def_id, tcx)
|
let prefix_layouts = substs.prefix_tys(def_id, tcx)
|
||||||
.map(|ty| self.layout_of(ty))
|
.map(|ty| self.layout_of(ty))
|
||||||
.chain(iter::once(Ok(discr_layout)))
|
.chain(iter::once(Ok(discr_layout)))
|
||||||
.chain(promoted_layouts)
|
.chain(promoted_layouts)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let mut prefix = self.univariant_uninterned(
|
let prefix = self.univariant_uninterned(
|
||||||
ty,
|
ty,
|
||||||
&prefix_layouts,
|
&prefix_layouts,
|
||||||
&ReprOptions::default(),
|
&ReprOptions::default(),
|
||||||
StructKind::AlwaysSized,
|
StructKind::AlwaysSized,
|
||||||
)?;
|
)?;
|
||||||
// FIXME(eddyb) need `MaybeUninit` around promoted types (see above).
|
|
||||||
prefix.largest_niche = None;
|
|
||||||
|
|
||||||
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
|
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// Incorrect handling of uninhabited types could cause us to mark generator
|
||||||
|
// types as entirely uninhabited, when they were in fact constructible. This
|
||||||
|
// caused us to hit "unreachable" code (illegal instruction on x86).
|
||||||
|
|
||||||
// run-pass
|
// run-pass
|
||||||
|
|
||||||
// compile-flags: --edition=2018
|
// compile-flags: --edition=2018
|
||||||
|
@ -19,7 +23,18 @@ async fn contains_never() {
|
||||||
let error2 = error;
|
let error2 = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
async fn overlap_never() {
|
||||||
|
let error1 = uninhabited_async();
|
||||||
|
noop().await;
|
||||||
|
let error2 = uninhabited_async();
|
||||||
|
drop(error1);
|
||||||
|
noop().await;
|
||||||
|
drop(error2);
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
fn main() {
|
fn main() {
|
||||||
contains_never();
|
contains_never();
|
||||||
|
overlap_never();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue