Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3e6a399

Browse files
dingxiangfei2009Dirbaio
andcommittedJan 14, 2025··
new layout
Co-authored-by: Dario Nieuwenhuis <[email protected]>
1 parent f319d1a commit 3e6a399

File tree

10 files changed

+374
-26
lines changed

10 files changed

+374
-26
lines changed
 

‎compiler/rustc_abi/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,8 +1552,10 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
15521552
/// a struct, and they all have space reserved for the tag.
15531553
/// For enums, the tag is the sole field of the layout.
15541554
Multiple {
1555+
/// Tag definition
15551556
tag: Scalar,
15561557
tag_encoding: TagEncoding<VariantIdx>,
1558+
/// Index of tag among fields
15571559
tag_field: usize,
15581560
variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
15591561
},
@@ -1597,6 +1599,7 @@ pub enum TagEncoding<VariantIdx: Idx> {
15971599
pub struct Niche {
15981600
pub offset: Size,
15991601
pub value: Primitive,
1602+
/// A range of valid values with both endpoints being inclusive
16001603
pub valid_range: WrappingRange,
16011604
}
16021605

@@ -1607,17 +1610,23 @@ impl Niche {
16071610
if niche.available(cx) > 0 { Some(niche) } else { None }
16081611
}
16091612

1613+
/// Compute how many values are outside the valid range, available for optimisation through niche filling
16101614
pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
16111615
let Self { value, valid_range: v, .. } = *self;
16121616
let size = value.size(cx);
16131617
assert!(size.bits() <= 128);
16141618
let max_value = size.unsigned_int_max();
16151619

1616-
// Find out how many values are outside the valid range.
16171620
let niche = v.end.wrapping_add(1)..v.start;
16181621
niche.end.wrapping_sub(niche.start) & max_value
16191622
}
16201623

1624+
/// Try to enlarge the valid value range to include another `count` values,
1625+
/// so that they can be used for niche-filling optimisation.
1626+
/// `None` signals impossibility of reservation.
1627+
/// Otherwise, `Some((start, scalar))` signifies that a reservation is possible,
1628+
/// the first value in the reservation is `start`, and the new scalar including
1629+
/// the reserved values is defined in `scalar`.
16211630
pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
16221631
assert!(count > 0);
16231632

‎compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,8 @@ declare_features! (
447447
(unstable, const_try, "1.56.0", Some(74935)),
448448
/// Allows coroutines to be cloned.
449449
(unstable, coroutine_clone, "1.65.0", Some(95360)),
450+
/// Allows aggressive merging coroutine saved slots
451+
(unstable, coroutine_new_layout, "CURRENT_RUSTC_VERSION", Some(99999)),
450452
/// Allows defining coroutines.
451453
(unstable, coroutines, "1.21.0", Some(43122)),
452454
/// Allows function attribute `#[coverage(on/off)]`, to control coverage

‎compiler/rustc_middle/src/mir/query.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_index::bit_set::BitMatrix;
1111
use rustc_index::{Idx, IndexVec};
1212
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1313
use rustc_span::{Span, Symbol};
14+
use rustc_type_ir::data_structures::IndexMap;
1415
use smallvec::SmallVec;
1516

1617
use super::{ConstValue, SourceInfo};
@@ -58,6 +59,10 @@ pub struct CoroutineLayout<'tcx> {
5859
#[type_foldable(identity)]
5960
#[type_visitable(ignore)]
6061
pub storage_conflicts: BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal>,
62+
63+
#[type_foldable(identity)]
64+
#[type_visitable(ignore)]
65+
pub relocated_upvars: IndexMap<CoroutineSavedLocal, CoroutineSavedLocal>,
6166
}
6267

6368
impl Debug for CoroutineLayout<'_> {

‎compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -975,9 +975,17 @@ fn compute_layout<'tcx>(
975975
suspension_point_at_block,
976976
} = liveness;
977977

978+
// We need to later establish the map between upvars in UNRESUMED and locals in other states.
979+
let local_upvar_map: UnordMap<_, _> = body
980+
.local_upvar_map
981+
.iter_enumerated()
982+
.filter_map(|(field, local)| local.map(|local| (local, field)))
983+
.collect();
984+
978985
// Gather live local types and their indices.
979986
let mut locals = IndexVec::<CoroutineSavedLocal, _>::new();
980987
let mut tys = IndexVec::<CoroutineSavedLocal, _>::new();
988+
let mut saved_local_upvar_map = UnordMap::default();
981989
for (saved_local, local) in saved_locals.iter_enumerated() {
982990
debug!("coroutine saved local {:?} => {:?}", saved_local, local);
983991

@@ -1005,6 +1013,10 @@ fn compute_layout<'tcx>(
10051013
debug!(?decl);
10061014

10071015
tys.push(decl);
1016+
1017+
if let Some(&field) = local_upvar_map.get(&local) {
1018+
saved_local_upvar_map.insert(field, saved_local);
1019+
}
10081020
}
10091021
// These are the "saved locals" sourced from the UNRESUMED state.
10101022
let upvar_saved_locals: IndexVec<FieldIdx, CoroutineSavedLocal> = upvar_tys
@@ -1057,8 +1069,7 @@ fn compute_layout<'tcx>(
10571069
SourceInfo::outermost(body_span.shrink_to_hi()),
10581070
SourceInfo::outermost(body_span.shrink_to_hi()),
10591071
]
1060-
.iter()
1061-
.copied()
1072+
.into_iter()
10621073
.collect();
10631074

10641075
// Build the coroutine variant field list.
@@ -1100,17 +1111,24 @@ fn compute_layout<'tcx>(
11001111
field_names.get_or_insert_with(saved_local, || var.name);
11011112
}
11021113
}
1103-
for (capture, saved_local) in upvar_infos.iter().zip(upvar_saved_locals) {
1114+
for (capture, &saved_local) in upvar_infos.iter().zip(&upvar_saved_locals) {
11041115
field_names.get_or_insert_with(saved_local, || capture.var_ident.name);
11051116
}
11061117
debug!(field_names = ?field_names.debug_map_view());
11071118

1119+
let relocated_upvars = upvar_saved_locals
1120+
.iter_enumerated()
1121+
.filter_map(|(field, &source)| {
1122+
saved_local_upvar_map.get(&field).map(|&dest| (source, dest))
1123+
})
1124+
.collect();
11081125
let layout = CoroutineLayout {
11091126
field_tys: tys,
11101127
field_names,
11111128
variant_fields,
11121129
variant_source_info,
11131130
storage_conflicts,
1131+
relocated_upvars,
11141132
};
11151133
debug!(?layout);
11161134

‎compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ symbols! {
693693
core_panic_macro,
694694
coroutine,
695695
coroutine_clone,
696+
coroutine_new_layout,
696697
coroutine_resume,
697698
coroutine_return,
698699
coroutine_state,

‎compiler/rustc_ty_utils/src/layout.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(unused)]
12
use std::fmt::Debug;
23
use std::iter;
34

@@ -31,6 +32,7 @@ use crate::errors::{
3132
MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType,
3233
};
3334

35+
mod coroutine;
3436
mod invariant;
3537

3638
pub(crate) fn provide(providers: &mut Providers) {
@@ -397,7 +399,13 @@ fn layout_of_uncached<'tcx>(
397399
tcx.mk_layout(unit)
398400
}
399401

400-
ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
402+
ty::Coroutine(def_id, args) => {
403+
// if tcx.features().coroutine_new_layout() {
404+
coroutine::coroutine_layout(cx, ty, def_id, args)?
405+
// } else {
406+
// coroutine_layout(cx, ty, def_id, args)?
407+
// }
408+
}
401409

402410
ty::Closure(_, args) => {
403411
let tys = args.as_closure().upvar_tys();
@@ -1168,8 +1176,10 @@ fn variant_info_for_coroutine<'tcx>(
11681176
.zip_eq(upvar_names)
11691177
.enumerate()
11701178
.map(|(field_idx, (_, name))| {
1171-
let field_layout = layout.field(cx, field_idx);
1172-
let offset = layout.fields.offset(field_idx);
1179+
// Upvars occupies the Unresumed variant at index zero
1180+
let variant_layout = layout.for_variant(cx, VariantIdx::ZERO);
1181+
let field_layout = variant_layout.field(cx, field_idx);
1182+
let offset = variant_layout.fields.offset(field_idx);
11731183
upvars_size = upvars_size.max(offset + field_layout.size);
11741184
FieldInfo {
11751185
kind: FieldKind::Upvar,
@@ -1189,12 +1199,11 @@ fn variant_info_for_coroutine<'tcx>(
11891199
let variant_layout = layout.for_variant(cx, variant_idx);
11901200
let mut variant_size = Size::ZERO;
11911201
let fields = variant_def
1192-
.iter()
1193-
.enumerate()
1202+
.iter_enumerated()
11941203
.map(|(field_idx, local)| {
11951204
let field_name = coroutine.field_names[*local];
1196-
let field_layout = variant_layout.field(cx, field_idx);
1197-
let offset = variant_layout.fields.offset(field_idx);
1205+
let field_layout = variant_layout.field(cx, field_idx.index());
1206+
let offset = variant_layout.fields.offset(field_idx.index());
11981207
// The struct is as large as the last field's end
11991208
variant_size = variant_size.max(offset + field_layout.size);
12001209
FieldInfo {
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
use std::cmp::Reverse;
2+
use std::collections::BTreeSet;
3+
use std::fmt::Debug;
4+
use std::ops::Bound;
5+
6+
use rustc_abi::{
7+
BackendRepr, FieldIdx, FieldsShape, Integer, Layout, LayoutData, Primitive, Scalar, Size,
8+
TagEncoding, TyAndLayout, Variants, WrappingRange,
9+
};
10+
use rustc_index::bit_set::BitSet;
11+
use rustc_index::{Idx, IndexVec};
12+
use rustc_middle::mir::CoroutineSavedLocal;
13+
use rustc_middle::ty::layout::{HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf};
14+
use rustc_middle::ty::{EarlyBinder, GenericArgsRef, Ty};
15+
use tracing::{debug, instrument};
16+
17+
use super::error;
18+
19+
#[instrument(level = "debug", skip(cx))]
20+
pub(super) fn coroutine_layout<'tcx>(
21+
cx: &LayoutCx<'tcx>,
22+
ty: Ty<'tcx>,
23+
def_id: rustc_hir::def_id::DefId,
24+
args: GenericArgsRef<'tcx>,
25+
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
26+
let tcx = cx.tcx();
27+
let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else {
28+
return Err(error(cx, LayoutError::Unknown(ty)));
29+
};
30+
let mut relocated_upvars = info.relocated_upvars.clone();
31+
for (&source, &dest) in &info.relocated_upvars {
32+
relocated_upvars.insert(dest, source);
33+
}
34+
35+
let tcx = cx.tcx();
36+
let field_layouts: IndexVec<CoroutineSavedLocal, _> = info
37+
.field_tys
38+
.iter_enumerated()
39+
.map(|(saved_local, ty)| {
40+
let ty = EarlyBinder::bind(ty.ty).instantiate(tcx, args);
41+
cx.spanned_layout_of(ty, info.field_tys[saved_local].source_info.span)
42+
})
43+
.try_collect()?;
44+
let layouts: IndexVec<CoroutineSavedLocal, _> =
45+
field_layouts.iter().map(|data| data.layout.clone()).collect();
46+
47+
let field_sort_keys: IndexVec<CoroutineSavedLocal, _>;
48+
let mut saved_locals: Vec<_>;
49+
// ## The heuristic on which saved locals get allocation first ##
50+
// 1. the alignment
51+
// Intuitively data with a larger alignment asks for a larger block of contiguous memory.
52+
// It is easier to get large blocks early in the beginning, but it will get harder to
53+
// recover them as fragmentation creeps in when data with smaller alignment occupies
54+
// the large chunks.
55+
// 2. the size
56+
// The size also poses restriction on layout, but not as potent as alignment.
57+
// 3. the degree of conflicts
58+
// This metric is the number of confliciting saved locals with a given saved local.
59+
// Preferring allocating highly conflicting data over those that are less and more
60+
// transient in nature will keep the fragmentation contained in neighbourhoods of a layout.
61+
(saved_locals, field_sort_keys) = field_layouts
62+
.iter_enumerated()
63+
.map(|(saved_local, ty)| {
64+
(
65+
saved_local,
66+
(
67+
Reverse(ty.align.abi),
68+
Reverse(ty.size),
69+
Reverse(info.storage_conflicts.count(saved_local)),
70+
),
71+
)
72+
})
73+
.unzip();
74+
let mut uninhabited_or_zst = BitSet::new_empty(saved_locals.len());
75+
for (saved_local, ty) in field_layouts.iter_enumerated() {
76+
if ty.backend_repr.is_uninhabited() || ty.is_zst() {
77+
uninhabited_or_zst.insert(saved_local);
78+
}
79+
}
80+
saved_locals.sort_by_key(|&idx| &field_sort_keys[idx]);
81+
let max_discr = (info.variant_fields.len() - 1) as u128;
82+
let discr_int = Integer::fit_unsigned(max_discr);
83+
let tag = Scalar::Initialized {
84+
value: Primitive::Int(discr_int, false),
85+
valid_range: WrappingRange { start: 0, end: max_discr },
86+
};
87+
let tag_layout = TyAndLayout {
88+
ty: discr_int.to_ty(tcx, false),
89+
layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
90+
};
91+
// This will be *the* align of the entire coroutine,
92+
// which is the maximal alignment of all saved locals.
93+
// We need to also consider the tag layout alignment.
94+
let align = saved_locals
95+
.get(0)
96+
.map(|&idx| layouts[idx].align.max(tag_layout.align))
97+
.unwrap_or(tag_layout.align);
98+
99+
// ## The blocked map, or the reservation map ##
100+
// This map from saved locals to memory layout records the reservation
101+
// status of the coroutine state memory, down to the byte granularity.
102+
// `Slot`s are inserted to mark ranges of memory that a particular saved local
103+
// shall not have overlapping memory allocation, due to the liveness of
104+
// other conflicting saved locals.
105+
// Therefore, we can try to make reservation for this saved local
106+
// by inspecting the gaps before, between, and after those blocked-out memory ranges.
107+
let mut blocked: IndexVec<CoroutineSavedLocal, BTreeSet<Slot>> =
108+
IndexVec::from_elem_n(BTreeSet::new(), saved_locals.len());
109+
let mut has_assignment = BitSet::new_empty(saved_locals.len());
110+
let mut tag_blocked = BTreeSet::new();
111+
let mut assignment = IndexVec::from_elem_n(Slot { start: 0, end: 0 }, saved_locals.len());
112+
for (idx, &current_local) in saved_locals.iter().enumerate() {
113+
if uninhabited_or_zst.contains(current_local) {
114+
// Do not bother to compute on uninhabited data.
115+
// They will not get allocation after all.
116+
// By default, a ZST occupies the beginning of the coroutine state.
117+
continue;
118+
}
119+
let layout_data = &field_layouts[current_local];
120+
121+
let candidate = if let Some(&another_local) = relocated_upvars.get(&current_local)
122+
&& has_assignment.contains(another_local)
123+
{
124+
assignment[another_local]
125+
} else {
126+
find_lowest_viable_allocation(&layout_data, &blocked[current_local])
127+
};
128+
// The discriminant is certainly conflicting with all the saved locals
129+
merge_slot_in(&mut tag_blocked, candidate);
130+
for &other_local in &saved_locals[idx + 1..] {
131+
if info.storage_conflicts.contains(current_local, other_local) {
132+
merge_slot_in(&mut blocked[other_local], candidate);
133+
}
134+
}
135+
// Adjustment to the layout of this field by shifting them into the chosen slot
136+
assignment[current_local] = candidate;
137+
has_assignment.insert(current_local);
138+
}
139+
debug!(assignment = ?assignment.debug_map_view());
140+
141+
// Find a slot for discriminant, also known as the tag.
142+
let tag_candidate = find_lowest_viable_allocation(&tag_layout, &tag_blocked);
143+
debug!(tag = ?tag_candidate);
144+
145+
// Assemble the layout for each coroutine state
146+
let variants: IndexVec<_, LayoutData<_, _>> = info
147+
.variant_fields
148+
.iter_enumerated()
149+
.map(|(index, fields)| {
150+
let size = Size::from_bytes(
151+
fields
152+
.iter()
153+
.map(|&saved_local| assignment[saved_local].end)
154+
.max()
155+
.unwrap_or(0)
156+
.max(tag_candidate.end),
157+
)
158+
.align_to(align.abi);
159+
let offsets: IndexVec<_, _> = fields
160+
.iter()
161+
.map(|&saved_local| Size::from_bytes(assignment[saved_local].start))
162+
.collect();
163+
let memory_index = IndexVec::from_fn_n(|n: FieldIdx| (n.index() as u32), offsets.len());
164+
LayoutData {
165+
// We are aware of specialized layouts such as scalar pairs but this is still
166+
// in development.
167+
// Let us hold off from further optimisation until more information is available.
168+
fields: FieldsShape::Arbitrary { offsets, memory_index },
169+
variants: Variants::Single { index },
170+
backend_repr: BackendRepr::Memory { sized: true },
171+
largest_niche: None,
172+
align,
173+
size,
174+
max_repr_align: None,
175+
unadjusted_abi_align: align.abi,
176+
}
177+
})
178+
.collect();
179+
let size = variants
180+
.iter()
181+
.map(|data| data.size)
182+
.max()
183+
.unwrap_or(Size::ZERO)
184+
.max(Size::from_bytes(tag_candidate.end))
185+
.align_to(align.abi);
186+
let layout = tcx.mk_layout(LayoutData {
187+
fields: FieldsShape::Arbitrary {
188+
offsets: [Size::from_bytes(tag_candidate.start)].into(),
189+
memory_index: [0].into(),
190+
},
191+
variants: Variants::Multiple {
192+
tag,
193+
tag_encoding: TagEncoding::Direct,
194+
tag_field: 0,
195+
variants,
196+
},
197+
backend_repr: BackendRepr::Memory { sized: true },
198+
// Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to
199+
// self-referentiality), getting the discriminant can cause aliasing violations.
200+
// `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that
201+
// would do the same for us here.
202+
// See <https://github.com/rust-lang/rust/issues/63818>, <https://github.com/rust-lang/miri/issues/3780>.
203+
// FIXME(#125735): Remove when <https://github.com/rust-lang/rust/issues/125735>
204+
// is implemented and aliased coroutine fields are wrapped in `UnsafePinned`.
205+
// NOTE(@dingxiangfei2009): I believe there is still niche, which is the tag,
206+
// but I am not sure how much benefit is there for us to grab.
207+
largest_niche: None,
208+
align,
209+
size,
210+
max_repr_align: None,
211+
unadjusted_abi_align: align.abi,
212+
});
213+
debug!("coroutine layout ({:?}): {:#?}", ty, layout);
214+
Ok(layout)
215+
}
216+
217+
/// An occupied slot in the coroutine memory at some yield point
218+
#[derive(PartialEq, Eq, Copy, Clone)]
219+
struct Slot {
220+
/// Beginning of the memory slot, inclusive
221+
start: u64,
222+
/// End of the memory slot, exclusive or one byte past the data
223+
end: u64,
224+
}
225+
226+
impl PartialOrd for Slot {
227+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
228+
(self.start, self.end).partial_cmp(&(other.start, other.end))
229+
}
230+
}
231+
232+
impl Ord for Slot {
233+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
234+
(self.start, self.end).cmp(&(other.start, other.end))
235+
}
236+
}
237+
238+
impl Debug for Slot {
239+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240+
f.debug_tuple("Slot").field(&self.start).field(&self.end).finish()
241+
}
242+
}
243+
244+
impl Slot {
245+
fn overlap_with(&self, other: &Self) -> bool {
246+
if self.start == self.end || other.start == other.end {
247+
return false;
248+
}
249+
self.contains_point(other.start) || other.contains_point(self.start)
250+
}
251+
fn contains_point(&self, point: u64) -> bool {
252+
self.start <= point && point < self.end
253+
}
254+
}
255+
256+
fn merge_slot_in(slots: &mut BTreeSet<Slot>, slot: Slot) {
257+
let start = Slot { start: slot.start, end: slot.start };
258+
let end = Slot { start: slot.end, end: slot.end };
259+
let one_past_end = Slot { start: slot.end + 1, end: slot.end + 1 };
260+
let (range_start, replace_start) = if let Some(prev) = slots.range(..start).next_back()
261+
&& (prev.end == slot.start || prev.contains_point(slot.start))
262+
{
263+
(Bound::Included(prev), prev.start)
264+
} else {
265+
(Bound::Included(&start), slot.start)
266+
};
267+
let (range_end, replace_end) = if let Some(next) = slots.range(..one_past_end).next_back()
268+
&& next.start == slot.end
269+
{
270+
(Bound::Included(next), next.end)
271+
} else if let Some(prev) = slots.range(..end).next_back()
272+
&& prev.contains_point(slot.end)
273+
{
274+
(Bound::Included(prev), prev.end)
275+
} else {
276+
(Bound::Included(&end), slot.end)
277+
};
278+
let to_remove: Vec<_> = slots.range((range_start, range_end)).copied().collect();
279+
for slot in to_remove {
280+
slots.remove(&slot);
281+
}
282+
slots.insert(Slot { start: replace_start, end: replace_end });
283+
}
284+
285+
fn find_lowest_viable_allocation<F: Idx, V: Idx>(
286+
layout: &LayoutData<F, V>,
287+
blocked: &BTreeSet<Slot>,
288+
) -> Slot {
289+
let size = layout.size.bytes();
290+
let align = layout.align.abi;
291+
let mut candidate = Slot { start: 0, end: size };
292+
for slot in blocked {
293+
if slot.overlap_with(&candidate) {
294+
let start = Size::from_bytes(slot.end).align_to(align).bytes();
295+
candidate = Slot { start, end: start + size };
296+
} else {
297+
break;
298+
}
299+
}
300+
candidate
301+
}

‎tests/ui/async-await/future-sizes/async-awaiting-fut.stdout

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ print-type-size field `.value`: 2052 bytes
1414
print-type-size type: `{async fn body of calls_fut<{async fn body of big_fut()}>()}`: 2052 bytes, alignment: 1 bytes
1515
print-type-size discriminant: 1 bytes
1616
print-type-size variant `Unresumed`: 2051 bytes
17-
print-type-size upvar `.fut`: 1 bytes, offset: 0 bytes, alignment: 1 bytes
1817
print-type-size padding: 1026 bytes
1918
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
19+
print-type-size upvar `.fut`: 1025 bytes, offset: 1027 bytes, alignment: 1 bytes
2020
print-type-size variant `Suspend0`: 1027 bytes
2121
print-type-size local `.fut`: 1025 bytes
2222
print-type-size local `..coroutine_field4`: 1 bytes, type: bool
@@ -29,8 +29,8 @@ print-type-size variant `Suspend2`: 1027 bytes
2929
print-type-size local `.fut`: 1025 bytes
3030
print-type-size local `..coroutine_field4`: 1 bytes, type: bool
3131
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()}
32-
print-type-size variant `Returned`: 0 bytes
33-
print-type-size variant `Panicked`: 0 bytes
32+
print-type-size variant `Returned`: 2051 bytes
33+
print-type-size variant `Panicked`: 2051 bytes
3434
print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes
3535
print-type-size field `.value`: 1025 bytes
3636
print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes
@@ -40,10 +40,10 @@ print-type-size field `.value`: 1025 bytes
4040
print-type-size type: `{async fn body of big_fut()}`: 1025 bytes, alignment: 1 bytes
4141
print-type-size discriminant: 1 bytes
4242
print-type-size variant `Unresumed`: 1024 bytes
43-
print-type-size upvar `.arg`: 1 bytes, offset: 0 bytes, alignment: 1 bytes
4443
print-type-size local `.arg`: 1024 bytes
45-
print-type-size variant `Returned`: 0 bytes
46-
print-type-size variant `Panicked`: 0 bytes
44+
print-type-size upvar `.arg`: 1024 bytes, offset: 1 bytes, alignment: 1 bytes
45+
print-type-size variant `Returned`: 1024 bytes
46+
print-type-size variant `Panicked`: 1024 bytes
4747
print-type-size type: `std::mem::ManuallyDrop<[u8; 1024]>`: 1024 bytes, alignment: 1 bytes
4848
print-type-size field `.value`: 1024 bytes
4949
print-type-size type: `std::mem::MaybeUninit<[u8; 1024]>`: 1024 bytes, alignment: 1 bytes

‎tests/ui/async-await/future-sizes/large-arg.stdout

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ print-type-size field `.value`: 1027 bytes
1414
print-type-size type: `{async fn body of a<[u8; 1024]>()}`: 1027 bytes, alignment: 1 bytes
1515
print-type-size discriminant: 1 bytes
1616
print-type-size variant `Unresumed`: 1024 bytes
17-
print-type-size upvar `.t`: 1 bytes, offset: 0 bytes, alignment: 1 bytes
1817
print-type-size local `.t`: 1024 bytes
18+
print-type-size upvar `.t`: 1024 bytes, offset: 1 bytes, alignment: 1 bytes
1919
print-type-size variant `Suspend0`: 1026 bytes
2020
print-type-size local `.__awaitee`: 1026 bytes, type: {async fn body of b<[u8; 1024]>()}
21-
print-type-size variant `Returned`: 0 bytes
22-
print-type-size variant `Panicked`: 0 bytes
21+
print-type-size variant `Returned`: 1024 bytes
22+
print-type-size variant `Panicked`: 1024 bytes
2323
print-type-size type: `std::mem::ManuallyDrop<{async fn body of b<[u8; 1024]>()}>`: 1026 bytes, alignment: 1 bytes
2424
print-type-size field `.value`: 1026 bytes
2525
print-type-size type: `std::mem::MaybeUninit<{async fn body of b<[u8; 1024]>()}>`: 1026 bytes, alignment: 1 bytes
@@ -29,12 +29,12 @@ print-type-size field `.value`: 1026 bytes
2929
print-type-size type: `{async fn body of b<[u8; 1024]>()}`: 1026 bytes, alignment: 1 bytes
3030
print-type-size discriminant: 1 bytes
3131
print-type-size variant `Unresumed`: 1024 bytes
32-
print-type-size upvar `.t`: 1 bytes, offset: 0 bytes, alignment: 1 bytes
3332
print-type-size local `.t`: 1024 bytes
33+
print-type-size upvar `.t`: 1024 bytes, offset: 1 bytes, alignment: 1 bytes
3434
print-type-size variant `Suspend0`: 1025 bytes
3535
print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body of c<[u8; 1024]>()}
36-
print-type-size variant `Returned`: 0 bytes
37-
print-type-size variant `Panicked`: 0 bytes
36+
print-type-size variant `Returned`: 1024 bytes
37+
print-type-size variant `Panicked`: 1024 bytes
3838
print-type-size type: `std::mem::ManuallyDrop<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes
3939
print-type-size field `.value`: 1025 bytes
4040
print-type-size type: `std::mem::MaybeUninit<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes
@@ -49,10 +49,10 @@ print-type-size variant `Pending`: 0 bytes
4949
print-type-size type: `{async fn body of c<[u8; 1024]>()}`: 1025 bytes, alignment: 1 bytes
5050
print-type-size discriminant: 1 bytes
5151
print-type-size variant `Unresumed`: 1024 bytes
52-
print-type-size upvar `.t`: 1 bytes, offset: 0 bytes, alignment: 1 bytes
5352
print-type-size local `.t`: 1024 bytes
54-
print-type-size variant `Returned`: 0 bytes
55-
print-type-size variant `Panicked`: 0 bytes
53+
print-type-size upvar `.t`: 1024 bytes, offset: 1 bytes, alignment: 1 bytes
54+
print-type-size variant `Returned`: 1024 bytes
55+
print-type-size variant `Panicked`: 1024 bytes
5656
print-type-size type: `std::mem::ManuallyDrop<[u8; 1024]>`: 1024 bytes, alignment: 1 bytes
5757
print-type-size field `.value`: 1024 bytes
5858
print-type-size type: `std::mem::MaybeUninit<[u8; 1024]>`: 1024 bytes, alignment: 1 bytes
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
compile_error!("this is an experimental flag that has no obvious user-facing changes");
3+
}

0 commit comments

Comments
 (0)
Please sign in to comment.