Skip to content

Commit 6fae7f8

Browse files
committed
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.
1 parent c43753f commit 6fae7f8

File tree

5 files changed

+37
-10
lines changed

5 files changed

+37
-10
lines changed

Diff for: src/libcore/mem/maybe_uninit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ use crate::mem::ManuallyDrop;
208208
/// guarantee may evolve.
209209
#[allow(missing_debug_implementations)]
210210
#[stable(feature = "maybe_uninit", since = "1.36.0")]
211+
// Lang item so we can wrap other types in it. This is useful for generators.
212+
#[cfg_attr(not(bootstrap), lang = "maybe_uninit")]
211213
#[derive(Copy)]
212214
#[repr(transparent)]
213215
pub union MaybeUninit<T> {

Diff for: src/librustc/middle/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ language_item_table! {
365365

366366
ManuallyDropItem, "manually_drop", manually_drop, Target::Struct;
367367

368+
MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union;
369+
368370
DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait;
369371

370372
// Align offset for stride != 1, must not panic.

Diff for: src/librustc/ty/context.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -2347,18 +2347,17 @@ impl<'tcx> TyCtxt<'tcx> {
23472347
self.mk_ty(Foreign(def_id))
23482348
}
23492349

2350-
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
2351-
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
2352-
let adt_def = self.adt_def(def_id);
2353-
let substs = InternalSubsts::for_item(self, def_id, |param, substs| {
2350+
fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
2351+
let adt_def = self.adt_def(wrapper_def_id);
2352+
let substs = InternalSubsts::for_item(self, wrapper_def_id, |param, substs| {
23542353
match param.kind {
23552354
GenericParamDefKind::Lifetime |
23562355
GenericParamDefKind::Const => {
23572356
bug!()
23582357
}
23592358
GenericParamDefKind::Type { has_default, .. } => {
23602359
if param.index == 0 {
2361-
ty.into()
2360+
ty_param.into()
23622361
} else {
23632362
assert!(has_default);
23642363
self.type_of(param.def_id).subst(self, substs).into()
@@ -2369,6 +2368,18 @@ impl<'tcx> TyCtxt<'tcx> {
23692368
self.mk_ty(Adt(adt_def, substs))
23702369
}
23712370

2371+
#[inline]
2372+
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
2373+
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
2374+
self.mk_generic_adt(def_id, ty)
2375+
}
2376+
2377+
#[inline]
2378+
pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
2379+
let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem);
2380+
self.mk_generic_adt(def_id, ty)
2381+
}
2382+
23722383
#[inline]
23732384
pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
23742385
self.mk_ty(RawPtr(tm))

Diff for: src/librustc/ty/layout.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -1406,24 +1406,21 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
14061406
Abi::Scalar(s) => s.clone(),
14071407
_ => bug!(),
14081408
};
1409-
// FIXME(eddyb) wrap each promoted type in `MaybeUninit` so that they
1410-
// don't poison the `largest_niche` or `abi` fields of `prefix`.
14111409
let promoted_layouts = ineligible_locals.iter()
14121410
.map(|local| subst_field(info.field_tys[local]))
1411+
.map(|ty| tcx.mk_maybe_uninit(ty))
14131412
.map(|ty| self.layout_of(ty));
14141413
let prefix_layouts = substs.prefix_tys(def_id, tcx)
14151414
.map(|ty| self.layout_of(ty))
14161415
.chain(iter::once(Ok(discr_layout)))
14171416
.chain(promoted_layouts)
14181417
.collect::<Result<Vec<_>, _>>()?;
1419-
let mut prefix = self.univariant_uninterned(
1418+
let prefix = self.univariant_uninterned(
14201419
ty,
14211420
&prefix_layouts,
14221421
&ReprOptions::default(),
14231422
StructKind::AlwaysSized,
14241423
)?;
1425-
// FIXME(eddyb) need `MaybeUninit` around promoted types (see above).
1426-
prefix.largest_niche = None;
14271424

14281425
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
14291426

Diff for: src/test/ui/async-await/issues/issue-59972.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Incorrect handling of uninhabited types could cause us to mark generator
2+
// types as entirely uninhabited, when they were in fact constructible. This
3+
// caused us to hit "unreachable" code (illegal instruction on x86).
4+
15
// run-pass
26

37
// compile-flags: --edition=2018
@@ -19,7 +23,18 @@ async fn contains_never() {
1923
let error2 = error;
2024
}
2125

26+
#[allow(unused)]
27+
async fn overlap_never() {
28+
let error1 = uninhabited_async();
29+
noop().await;
30+
let error2 = uninhabited_async();
31+
drop(error1);
32+
noop().await;
33+
drop(error2);
34+
}
35+
2236
#[allow(unused_must_use)]
2337
fn main() {
2438
contains_never();
39+
overlap_never();
2540
}

0 commit comments

Comments
 (0)