Skip to content

Commit 37b43cc

Browse files
relocate upvars to Unresumed state and make coroutine prefix trivial
Co-authored-by: Dario Nieuwenhuis <[email protected]>
1 parent 77a4553 commit 37b43cc

File tree

61 files changed

+1150
-508
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1150
-508
lines changed

compiler/rustc_borrowck/src/lib.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::ops::{ControlFlow, Deref};
2424
use rustc_abi::FieldIdx;
2525
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2626
use rustc_data_structures::graph::dominators::Dominators;
27+
use rustc_data_structures::unord::UnordMap;
2728
use rustc_errors::LintDiagnostic;
2829
use rustc_hir as hir;
2930
use rustc_hir::CRATE_HIR_ID;
@@ -262,6 +263,7 @@ fn do_mir_borrowck<'tcx>(
262263
regioncx: &regioncx,
263264
used_mut: Default::default(),
264265
used_mut_upvars: SmallVec::new(),
266+
local_from_upvars: UnordMap::default(),
265267
borrow_set: &borrow_set,
266268
upvars: &[],
267269
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
@@ -286,6 +288,11 @@ fn do_mir_borrowck<'tcx>(
286288
promoted_mbcx.report_move_errors();
287289
}
288290

291+
let mut local_from_upvars = UnordMap::default();
292+
for (field, &local) in body.local_upvar_map.iter_enumerated() {
293+
let Some(local) = local else { continue };
294+
local_from_upvars.insert(local, field);
295+
}
289296
let mut mbcx = MirBorrowckCtxt {
290297
infcx: &infcx,
291298
body,
@@ -300,6 +307,7 @@ fn do_mir_borrowck<'tcx>(
300307
regioncx: &regioncx,
301308
used_mut: Default::default(),
302309
used_mut_upvars: SmallVec::new(),
310+
local_from_upvars,
303311
borrow_set: &borrow_set,
304312
upvars: tcx.closure_captures(def),
305313
local_names,
@@ -554,6 +562,9 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
554562
/// If the function we're checking is a closure, then we'll need to report back the list of
555563
/// mutable upvars that have been used. This field keeps track of them.
556564
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
565+
/// Since upvars are moved to real locals, we need to map mutations to the locals back to
566+
/// the upvars, so that used_mut_upvars is up-to-date.
567+
local_from_upvars: UnordMap<Local, FieldIdx>,
557568
/// Region inference context. This contains the results from region inference and lets us e.g.
558569
/// find out which CFG points are contained in each borrow region.
559570
regioncx: &'a RegionInferenceContext<'tcx>,
@@ -2270,10 +2281,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
22702281
// If the local may have been initialized, and it is now currently being
22712282
// mutated, then it is justified to be annotated with the `mut`
22722283
// keyword, since the mutation may be a possible reassignment.
2273-
if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2274-
&& self.is_local_ever_initialized(local, state).is_some()
2275-
{
2276-
self.used_mut.insert(local);
2284+
if !matches!(is_local_mutation_allowed, LocalMutationIsAllowed::Yes) {
2285+
if self.is_local_ever_initialized(local, state).is_some() {
2286+
self.used_mut.insert(local);
2287+
} else if let Some(&field) = self.local_from_upvars.get(&local) {
2288+
self.used_mut_upvars.push(field);
2289+
}
22772290
}
22782291
}
22792292
RootPlace {
@@ -2291,6 +2304,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
22912304
projection: place_projection,
22922305
}) {
22932306
self.used_mut_upvars.push(field);
2307+
} else if let Some(&field) = self.local_from_upvars.get(&place_local) {
2308+
self.used_mut_upvars.push(field);
22942309
}
22952310
}
22962311
}

compiler/rustc_borrowck/src/type_check/mod.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use rustc_middle::ty::cast::CastTy;
2828
use rustc_middle::ty::fold::fold_regions;
2929
use rustc_middle::ty::visit::TypeVisitableExt;
3030
use rustc_middle::ty::{
31-
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
32-
Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserArgs,
31+
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
32+
GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserArgs,
3333
UserTypeAnnotationIndex,
3434
};
3535
use rustc_middle::{bug, span_bug};
@@ -1513,11 +1513,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
15131513
// It doesn't make sense to look at a field beyond the prefix;
15141514
// these require a variant index, and are not initialized in
15151515
// aggregate rvalues.
1516-
match args.as_coroutine().prefix_tys().get(field_index.as_usize()) {
1517-
Some(ty) => Ok(*ty),
1518-
None => Err(FieldAccessError::OutOfRange {
1519-
field_count: args.as_coroutine().prefix_tys().len(),
1520-
}),
1516+
let upvar_tys = &args.as_coroutine().upvar_tys();
1517+
if let Some(ty) = upvar_tys.get(field_index.as_usize()) {
1518+
Ok(*ty)
1519+
} else {
1520+
Err(FieldAccessError::OutOfRange { field_count: upvar_tys.len() })
15211521
}
15221522
}
15231523
AggregateKind::CoroutineClosure(_, args) => {

compiler/rustc_codegen_cranelift/src/base.rs

+3
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,9 @@ fn codegen_stmt<'tcx>(
896896
let variant_dest = lval.downcast_variant(fx, variant_index);
897897
(variant_index, variant_dest, active_field_index)
898898
}
899+
mir::AggregateKind::Coroutine(_def_id, _args) => {
900+
(FIRST_VARIANT, lval.downcast_variant(fx, FIRST_VARIANT), None)
901+
}
899902
_ => (FIRST_VARIANT, lval, None),
900903
};
901904
if active_field_index.is_some() {

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ use rustc_hir::def::{CtorKind, DefKind};
1212
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1313
use rustc_middle::bug;
1414
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout};
15-
use rustc_middle::ty::{
16-
self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
17-
};
15+
use rustc_middle::ty::{self, AdtKind, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility};
1816
use rustc_session::config::{self, DebugInfo, Lto};
1917
use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Symbol, hygiene};
2018
use rustc_symbol_mangling::typeid_for_trait_ref;
@@ -1103,7 +1101,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
11031101
closure_or_coroutine_di_node: &'ll DIType,
11041102
) -> SmallVec<&'ll DIType> {
11051103
let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() {
1106-
ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()),
1104+
ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().upvar_tys()),
11071105
ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
11081106
ty::CoroutineClosure(def_id, args) => (def_id, args.as_coroutine_closure().upvar_tys()),
11091107
_ => {

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs

-2
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,6 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
724724
let coroutine_layout =
725725
cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.kind_ty()).unwrap();
726726

727-
let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
728727
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
729728
let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();
730729

@@ -764,7 +763,6 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
764763
coroutine_type_and_layout,
765764
coroutine_type_di_node,
766765
coroutine_layout,
767-
common_upvar_names,
768766
);
769767

770768
let span = coroutine_layout.variant_source_info[variant_index].span;

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs

+2-32
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_
55
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
66
use rustc_codegen_ssa::traits::MiscCodegenMethods;
77
use rustc_hir::def::CtorKind;
8-
use rustc_index::IndexSlice;
98
use rustc_middle::bug;
109
use rustc_middle::mir::CoroutineLayout;
1110
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
1211
use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
13-
use rustc_span::Symbol;
1412

1513
use super::type_map::{DINodeCreationResult, UniqueTypeId};
1614
use super::{SmallVec, size_and_align_of};
@@ -286,7 +284,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
286284
coroutine_type_and_layout: TyAndLayout<'tcx>,
287285
coroutine_type_di_node: &'ll DIType,
288286
coroutine_layout: &CoroutineLayout<'tcx>,
289-
common_upvar_names: &IndexSlice<FieldIdx, Symbol>,
290287
) -> &'ll DIType {
291288
let variant_name = CoroutineArgs::variant_name(variant_index);
292289
let unique_type_id = UniqueTypeId::for_enum_variant_struct_type(
@@ -297,11 +294,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
297294

298295
let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index);
299296

300-
let coroutine_args = match coroutine_type_and_layout.ty.kind() {
301-
ty::Coroutine(_, args) => args.as_coroutine(),
302-
_ => unreachable!(),
303-
};
304-
305297
type_map::build_type_with_children(
306298
cx,
307299
type_map::stub(
@@ -316,7 +308,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
316308
),
317309
|cx, variant_struct_type_di_node| {
318310
// Fields that just belong to this variant/state
319-
let state_specific_fields: SmallVec<_> = (0..variant_layout.fields.count())
311+
(0..variant_layout.fields.count())
320312
.map(|field_index| {
321313
let coroutine_saved_local = coroutine_layout.variant_fields[variant_index]
322314
[FieldIdx::from_usize(field_index)];
@@ -339,29 +331,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
339331
None,
340332
)
341333
})
342-
.collect();
343-
344-
// Fields that are common to all states
345-
let common_fields: SmallVec<_> = coroutine_args
346-
.prefix_tys()
347-
.iter()
348-
.zip(common_upvar_names)
349-
.enumerate()
350-
.map(|(index, (upvar_ty, upvar_name))| {
351-
build_field_di_node(
352-
cx,
353-
variant_struct_type_di_node,
354-
upvar_name.as_str(),
355-
cx.size_and_align_of(upvar_ty),
356-
coroutine_type_and_layout.fields.offset(index),
357-
DIFlags::FlagZero,
358-
type_di_node(cx, upvar_ty),
359-
None,
360-
)
361-
})
362-
.collect();
363-
364-
state_specific_fields.into_iter().chain(common_fields).collect()
334+
.collect()
365335
},
366336
|cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
367337
)

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs

-4
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,6 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
188188
)
189189
};
190190

191-
let common_upvar_names =
192-
cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
193-
194191
// Build variant struct types
195192
let variant_struct_type_di_nodes: SmallVec<_> = variants
196193
.indices()
@@ -218,7 +215,6 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
218215
coroutine_type_and_layout,
219216
coroutine_type_di_node,
220217
coroutine_layout,
221-
common_upvar_names,
222218
),
223219
source_info,
224220
}

compiler/rustc_codegen_ssa/src/mir/operand.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range};
1010
use rustc_middle::mir::{self, ConstValue};
1111
use rustc_middle::ty::Ty;
1212
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
13-
use tracing::debug;
13+
use tracing::{debug, instrument};
1414

1515
use super::place::{PlaceRef, PlaceValue};
1616
use super::{FunctionCx, LocalRef};
@@ -569,13 +569,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
569569
}
570570

571571
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
572+
#[instrument(level = "debug", skip(self, bx), ret)]
572573
fn maybe_codegen_consume_direct(
573574
&mut self,
574575
bx: &mut Bx,
575576
place_ref: mir::PlaceRef<'tcx>,
576577
) -> Option<OperandRef<'tcx, Bx::Value>> {
577-
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
578-
579578
match self.locals[place_ref.local] {
580579
LocalRef::Operand(mut o) => {
581580
// Moves out of scalar and scalar pair fields are trivial.
@@ -618,13 +617,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
618617
}
619618
}
620619

620+
#[instrument(level = "debug", skip(self, bx), ret)]
621621
pub fn codegen_consume(
622622
&mut self,
623623
bx: &mut Bx,
624624
place_ref: mir::PlaceRef<'tcx>,
625625
) -> OperandRef<'tcx, Bx::Value> {
626-
debug!("codegen_consume(place_ref={:?})", place_ref);
627-
628626
let ty = self.monomorphized_place_ty(place_ref);
629627
let layout = bx.cx().layout_of(ty);
630628

@@ -643,13 +641,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
643641
bx.load_operand(place)
644642
}
645643

644+
#[instrument(level = "debug", skip(self, bx), ret)]
646645
pub fn codegen_operand(
647646
&mut self,
648647
bx: &mut Bx,
649648
operand: &mir::Operand<'tcx>,
650649
) -> OperandRef<'tcx, Bx::Value> {
651-
debug!("codegen_operand(operand={:?})", operand);
652-
653650
match *operand {
654651
mir::Operand::Copy(ref place) | mir::Operand::Move(ref place) => {
655652
self.codegen_consume(bx, place.as_ref())

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+3
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
166166
let variant_dest = dest.project_downcast(bx, variant_index);
167167
(variant_index, variant_dest, active_field_index)
168168
}
169+
mir::AggregateKind::Coroutine(_, _) => {
170+
(FIRST_VARIANT, dest.project_downcast(bx, FIRST_VARIANT), None)
171+
}
169172
_ => (FIRST_VARIANT, dest, None),
170173
};
171174
if active_field_index.is_some() {

compiler/rustc_const_eval/src/interpret/step.rs

+3
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
298298
let variant_dest = self.project_downcast(dest, variant_index)?;
299299
(variant_index, variant_dest, active_field_index)
300300
}
301+
mir::AggregateKind::Coroutine(_def_id, _args) => {
302+
(FIRST_VARIANT, self.project_downcast(dest, FIRST_VARIANT)?, None)
303+
}
301304
mir::AggregateKind::RawPtr(..) => {
302305
// Pointers don't have "fields" in the normal sense, so the
303306
// projection-based code below would either fail in projection

compiler/rustc_index/src/vec.rs

+35
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ impl<I: Idx, T> IndexVec<I, T> {
193193
pub fn append(&mut self, other: &mut Self) {
194194
self.raw.append(&mut other.raw);
195195
}
196+
197+
#[inline]
198+
pub fn debug_map_view(&self) -> IndexSliceMapView<'_, I, T> {
199+
IndexSliceMapView(self.as_slice())
200+
}
196201
}
197202

198203
/// `IndexVec` is often used as a map, so it provides some map-like APIs.
@@ -216,14 +221,44 @@ impl<I: Idx, T> IndexVec<I, Option<T>> {
216221
pub fn contains(&self, index: I) -> bool {
217222
self.get(index).and_then(Option::as_ref).is_some()
218223
}
224+
225+
#[inline]
226+
pub fn debug_map_view_compact(&self) -> IndexSliceMapViewCompact<'_, I, T> {
227+
IndexSliceMapViewCompact(self.as_slice())
228+
}
219229
}
220230

231+
pub struct IndexSliceMapView<'a, I: Idx, T>(&'a IndexSlice<I, T>);
232+
pub struct IndexSliceMapViewCompact<'a, I: Idx, T>(&'a IndexSlice<I, Option<T>>);
233+
221234
impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
222235
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
223236
fmt::Debug::fmt(&self.raw, fmt)
224237
}
225238
}
226239

240+
impl<'a, I: Idx, T: fmt::Debug> fmt::Debug for IndexSliceMapView<'a, I, T> {
241+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
242+
let mut entries = fmt.debug_map();
243+
for (idx, val) in self.0.iter_enumerated() {
244+
entries.entry(&idx, val);
245+
}
246+
entries.finish()
247+
}
248+
}
249+
250+
impl<'a, I: Idx, T: fmt::Debug> fmt::Debug for IndexSliceMapViewCompact<'a, I, T> {
251+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
252+
let mut entries = fmt.debug_map();
253+
for (idx, val) in self.0.iter_enumerated() {
254+
if let Some(val) = val {
255+
entries.entry(&idx, val);
256+
}
257+
}
258+
entries.finish()
259+
}
260+
}
261+
227262
impl<I: Idx, T> Deref for IndexVec<I, T> {
228263
type Target = IndexSlice<I, T>;
229264

compiler/rustc_middle/src/mir/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ pub struct Body<'tcx> {
371371
#[type_foldable(identity)]
372372
#[type_visitable(ignore)]
373373
pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
374+
375+
/// Coroutine local-upvar map
376+
pub local_upvar_map: IndexVec<FieldIdx, Option<Local>>,
374377
}
375378

376379
impl<'tcx> Body<'tcx> {
@@ -414,6 +417,7 @@ impl<'tcx> Body<'tcx> {
414417
tainted_by_errors,
415418
coverage_info_hi: None,
416419
function_coverage_info: None,
420+
local_upvar_map: IndexVec::new(),
417421
};
418422
body.is_polymorphic = body.has_non_region_param();
419423
body
@@ -445,6 +449,7 @@ impl<'tcx> Body<'tcx> {
445449
tainted_by_errors: None,
446450
coverage_info_hi: None,
447451
function_coverage_info: None,
452+
local_upvar_map: IndexVec::new(),
448453
};
449454
body.is_polymorphic = body.has_non_region_param();
450455
body

0 commit comments

Comments
 (0)