1
Fork 0

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:
Tyler Mandry 2019-07-26 19:36:26 -07:00
parent c43753f910
commit 6fae7f8071
5 changed files with 37 additions and 10 deletions

View file

@ -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> {

View file

@ -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.

View file

@ -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))

View file

@ -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);

View file

@ -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();
} }