about summary refs log tree commit diff
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
authorlrh2000 <lrh2000@pku.edu.cn>2021-05-05 23:50:44 +0800
committerlrh2000 <lrh2000@pku.edu.cn>2021-07-09 23:06:53 +0800
commit29856acffeb87541bb167c33f4fdb13c31ba6de0 (patch)
tree2bbb04127b4609350704b956985e38371cc62ca5 /compiler/rustc_middle
parent95fb1315217976ff4c268bb03c9b4132f0dfa9fd (diff)
downloadrust-29856acffeb87541bb167c33f4fdb13c31ba6de0.tar.gz
rust-29856acffeb87541bb167c33f4fdb13c31ba6de0.zip
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 commit names the upvars,
so we can expect to see something like
```
y::main::closure-0 {_captured_ref__b: 0x[...]}
```
Diffstat (limited to 'compiler/rustc_middle')
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs48
1 files changed, 48 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 0706a057dd0..0d4c6350507 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -159,6 +159,54 @@ impl CapturedPlace<'tcx> {
         place_to_string_for_capture(tcx, &self.place)
     }
 
+    /// Returns mangled names of captured upvars. Here are some examples:
+    ///  - `_captured_val__name__field`
+    ///  - `_captured_ref__name__field`
+    ///
+    /// The purpose is to use those names in debuginfo. They should be human-understandable.
+    /// Without the names, the end users may get confused when the debuggers just print some
+    /// pointers in closures or generators.
+    pub fn to_mangled_name(&self, tcx: TyCtxt<'tcx>) -> String {
+        let prefix = match self.info.capture_kind {
+            ty::UpvarCapture::ByValue(_) => "_captured_val__",
+            ty::UpvarCapture::ByRef(_) => "_captured_ref__",
+        };
+
+        let hir_id = match self.place.base {
+            HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+            base => bug!("Expected an upvar, found {:?}", base),
+        };
+        let name = tcx.hir().name(hir_id);
+
+        let mut ty = self.place.base_ty;
+        let mut fields = String::new();
+        for proj in self.place.projections.iter() {
+            match proj.kind {
+                HirProjectionKind::Field(idx, variant) => match ty.kind() {
+                    ty::Tuple(_) => fields = format!("{}__{}", fields, idx),
+                    ty::Adt(def, ..) => {
+                        fields = format!(
+                            "{}__{}",
+                            fields,
+                            def.variants[variant].fields[idx as usize].ident.name.as_str(),
+                        );
+                    }
+                    ty => {
+                        bug!("Unexpected type {:?} for `Field` projection", ty)
+                    }
+                },
+
+                // Ignore derefs for now, as they are likely caused by
+                // autoderefs that don't appear in the original code.
+                HirProjectionKind::Deref => {}
+                proj => bug!("Unexpected projection {:?} in captured place", proj),
+            }
+            ty = proj.ty;
+        }
+
+        prefix.to_owned() + &name.to_string() + &fields
+    }
+
     /// Returns the hir-id of the root variable for the captured place.
     /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
     pub fn get_root_variable(&self) -> hir::HirId {