Skip to content

Commit dafc7ee

Browse files
committed
Keep ZSTs at beginning of generator layout fields
Fixes #61793.
1 parent 1d9981f commit dafc7ee

File tree

2 files changed

+60
-20
lines changed

2 files changed

+60
-20
lines changed

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

+43-20
Original file line numberDiff line numberDiff line change
@@ -1311,10 +1311,19 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13111311
) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
13121312
use SavedLocalEligibility::*;
13131313
let tcx = self.tcx;
1314-
let recompute_memory_index = |offsets: &[Size]| -> Vec<u32> {
1314+
let recompute_memory_index = |offsets: &[Size], fields: &[TyLayout<'_>]| -> Vec<u32> {
13151315
debug!("recompute_memory_index({:?})", offsets);
1316+
debug!("fields = {:#?}", fields);
13161317
let mut inverse_index = (0..offsets.len() as u32).collect::<Vec<_>>();
1317-
inverse_index.sort_unstable_by_key(|i| offsets[*i as usize]);
1318+
inverse_index.sort_unstable_by_key(|i| {
1319+
// Place ZSTs before other fields at the same offset so all fields are
1320+
// in order by offset. Codegen expects this.
1321+
//
1322+
// In generators we can have ZST fields with nonzero offsets (these are
1323+
// fields specific to one variant that come after the prefix).
1324+
let zst = fields[*i as usize].is_zst();
1325+
(offsets[*i as usize], !zst)
1326+
});
13181327

13191328
let mut index = vec![0; offsets.len()];
13201329
for i in 0..index.len() {
@@ -1337,9 +1346,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13371346
let prefix_tys = substs.prefix_tys(def_id, tcx)
13381347
.chain(iter::once(substs.discr_ty(tcx)))
13391348
.chain(promoted_tys);
1349+
let prefix_layouts = prefix_tys
1350+
.map(|ty| self.layout_of(ty))
1351+
.collect::<Result<Vec<_>, _>>()?;
13401352
let prefix = self.univariant_uninterned(
13411353
ty,
1342-
&prefix_tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
1354+
&prefix_layouts,
13431355
&ReprOptions::default(),
13441356
StructKind::AlwaysSized)?;
13451357
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
@@ -1354,7 +1366,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13541366
let offsets_b = offsets.split_off(discr_index + 1);
13551367
let offsets_a = offsets;
13561368

1357-
let memory_index = recompute_memory_index(&offsets_a);
1369+
// Okay to use `prefix_layouts` here since we're accessing
1370+
// fields (0..discr_index + 1); the field indices will be the
1371+
// same.
1372+
let memory_index = recompute_memory_index(&offsets_a, &prefix_layouts);
1373+
13581374
let outer_fields = FieldPlacement::Arbitrary { offsets: offsets_a, memory_index };
13591375
(outer_fields, offsets_b)
13601376
}
@@ -1364,24 +1380,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13641380
let mut size = prefix.size;
13651381
let mut align = prefix.align;
13661382
let variants = info.variant_fields.iter_enumerated().map(|(index, variant_fields)| {
1367-
// Only include overlap-eligible fields when we compute our variant layout.
1368-
let variant_only_tys = variant_fields
1369-
.iter()
1370-
.filter(|local| {
1371-
match assignments[**local] {
1372-
Unassigned => bug!(),
1373-
Assigned(v) if v == index => true,
1374-
Assigned(_) => bug!("assignment does not match variant"),
1375-
Ineligible(_) => false,
1376-
}
1377-
})
1378-
.map(|local| subst_field(info.field_tys[*local]));
1383+
let mut variant_layouts = Vec::with_capacity(variant_fields.len());
1384+
let mut variant_only_layouts = Vec::with_capacity(variant_fields.len());
1385+
for local in variant_fields {
1386+
let ty = subst_field(info.field_tys[*local]);
1387+
let layout = self.layout_of(ty)?;
1388+
1389+
variant_layouts.push(layout);
1390+
1391+
// Only include overlap-eligible fields when we compute our variant layout.
1392+
let variant_only = match assignments[*local] {
1393+
Unassigned => bug!(),
1394+
Assigned(v) if v == index => true,
1395+
Assigned(_) => bug!("assignment does not match variant"),
1396+
Ineligible(_) => false,
1397+
};
1398+
if variant_only {
1399+
variant_only_layouts.push(layout);
1400+
}
1401+
}
13791402

13801403
let mut variant = self.univariant_uninterned(
13811404
ty,
1382-
&variant_only_tys
1383-
.map(|ty| self.layout_of(ty))
1384-
.collect::<Result<Vec<_>, _>>()?,
1405+
&variant_only_layouts,
13851406
&ReprOptions::default(),
13861407
StructKind::Prefixed(prefix_size, prefix_align.abi))?;
13871408
variant.variants = Variants::Single { index };
@@ -1408,7 +1429,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
14081429
}
14091430
}
14101431
}
1411-
let memory_index = recompute_memory_index(&combined_offsets);
1432+
let memory_index = recompute_memory_index(&combined_offsets, &variant_layouts);
14121433
variant.fields = FieldPlacement::Arbitrary { offsets: combined_offsets, memory_index };
14131434

14141435
size = size.max(variant.size);
@@ -1442,7 +1463,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
14421463
debug!("generator layout ({:?}): {:#?}", ty, layout);
14431464
Ok(layout)
14441465
}
1466+
}
14451467

1468+
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
14461469
/// This is invoked by the `layout_raw` query to record the final
14471470
/// layout of each type.
14481471
#[inline(always)]

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

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This regression test exposed an issue where ZSTs were not being placed at the
2+
// beinning of generator field layouts, causing an assertion error downstream.
3+
4+
// compile-pass
5+
// edition:2018
6+
7+
#![feature(async_await)]
8+
#![allow(unused)]
9+
10+
async fn foo<F>(_: &(), _: F) {}
11+
12+
fn main() {
13+
foo(&(), || {});
14+
async {
15+
foo(&(), || {}).await;
16+
};
17+
}

0 commit comments

Comments
 (0)