Auto merge of #85020 - lrh2000:named-upvars, r=tmandry

Name the captured upvars for closures/generators in debuginfo

Previously, debuggers print closures as something like
```
y::main::closure-0 (0x7fffffffdd34)
```
The pointer actually references to an upvar. It is not very obvious, especially for beginners.

It's because upvars don't have names before, as they are packed into a tuple. This PR names the upvars, so we can expect to see something like
```
y::main::closure-0 {_captured_ref__b: 0x[...]}
```

r? `@tmandry`
Discussed at https://github.com/rust-lang/rust/pull/84752#issuecomment-831639489 .
This commit is contained in:
bors 2021-08-14 07:01:36 +00:00
commit 99efc51dae
9 changed files with 276 additions and 23 deletions

View file

@ -1280,6 +1280,31 @@ fn prepare_struct_metadata(
// Tuples
//=-----------------------------------------------------------------------------
/// Returns names of captured upvars for closures and generators.
///
/// Here are some examples:
/// - `name__field1__field2` when the upvar is captured by value.
/// - `_ref__name__field` when the upvar is captured by reference.
fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<String> {
let body = tcx.optimized_mir(def_id);
body.var_debug_info
.iter()
.filter_map(|var| {
let is_ref = match var.value {
mir::VarDebugInfoContents::Place(place) if place.local == mir::Local::new(1) => {
// The projection is either `[.., Field, Deref]` or `[.., Field]`. It
// implies whether the variable is captured by value or by reference.
matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
}
_ => return None,
};
let prefix = if is_ref { "_ref__" } else { "" };
Some(prefix.to_owned() + &var.name.as_str())
})
.collect::<Vec<_>>()
}
/// Creates `MemberDescription`s for the fields of a tuple.
struct TupleMemberDescriptionFactory<'tcx> {
ty: Ty<'tcx>,
@ -1289,14 +1314,25 @@ struct TupleMemberDescriptionFactory<'tcx> {
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
let mut capture_names = match *self.ty.kind() {
ty::Generator(def_id, ..) | ty::Closure(def_id, ..) => {
Some(closure_saved_names_of_captured_variables(cx.tcx, def_id).into_iter())
}
_ => None,
};
let layout = cx.layout_of(self.ty);
self.component_types
.iter()
.enumerate()
.map(|(i, &component_type)| {
let (size, align) = cx.size_and_align_of(component_type);
let name = if let Some(names) = capture_names.as_mut() {
names.next().unwrap()
} else {
format!("__{}", i)
};
MemberDescription {
name: format!("__{}", i),
name,
type_metadata: type_metadata(cx, component_type, self.span),
offset: layout.fields.offset(i),
size,