about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src/debuginfo
diff options
context:
space:
mode:
authorJon Gjengset <jon@thesquareplanet.com>2020-09-01 09:49:42 -0400
committerJon Gjengset <jon@thesquareplanet.com>2020-09-01 09:49:42 -0400
commit010891f8b83d0795d8d92770755f0a0cc1d0a91d (patch)
tree62e5619a7dbcd0f1ca3df8863803c9bce980fcad /compiler/rustc_codegen_ssa/src/debuginfo
parent2f96ce89d03b248c269513b011d328bff2c8dc21 (diff)
parente88e908e66cd1e6e30d789b37bcd774951d01856 (diff)
downloadrust-010891f8b83d0795d8d92770755f0a0cc1d0a91d.tar.gz
rust-010891f8b83d0795d8d92770755f0a0cc1d0a91d.zip
Merge branch 'master' into stabilize-vecdeque-make_contiguous
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/debuginfo')
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs266
2 files changed, 268 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
new file mode 100644
index 00000000000..d1a0cf78d6a
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
@@ -0,0 +1,2 @@
+// FIXME(eddyb) find a place for this (or a way to replace it).
+pub mod type_names;
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
new file mode 100644
index 00000000000..fb8f5a62989
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -0,0 +1,266 @@
+// Type Names for Debug Info.
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
+
+// Compute the name of the type as it should be stored in debuginfo. Does not do
+// any caching, i.e., calling the function twice with the same type will also do
+// the work twice. The `qualified` parameter only affects the first level of the
+// type name, further levels (i.e., type parameters) are always fully qualified.
+pub fn compute_debuginfo_type_name<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    t: Ty<'tcx>,
+    qualified: bool,
+) -> String {
+    let mut result = String::with_capacity(64);
+    let mut visited = FxHashSet::default();
+    push_debuginfo_type_name(tcx, t, qualified, &mut result, &mut visited);
+    result
+}
+
+// Pushes the name of the type as it should be stored in debuginfo on the
+// `output` String. See also compute_debuginfo_type_name().
+pub fn push_debuginfo_type_name<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    t: Ty<'tcx>,
+    qualified: bool,
+    output: &mut String,
+    visited: &mut FxHashSet<Ty<'tcx>>,
+) {
+    // When targeting MSVC, emit C++ style type names for compatibility with
+    // .natvis visualizers (and perhaps other existing native debuggers?)
+    let cpp_like_names = tcx.sess.target.target.options.is_like_msvc;
+
+    match t.kind {
+        ty::Bool => output.push_str("bool"),
+        ty::Char => output.push_str("char"),
+        ty::Str => output.push_str("str"),
+        ty::Never => output.push_str("!"),
+        ty::Int(int_ty) => output.push_str(int_ty.name_str()),
+        ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()),
+        ty::Float(float_ty) => output.push_str(float_ty.name_str()),
+        ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
+        ty::Adt(def, substs) => {
+            push_item_name(tcx, def.did, qualified, output);
+            push_type_params(tcx, substs, output, visited);
+        }
+        ty::Tuple(component_types) => {
+            if cpp_like_names {
+                output.push_str("tuple<");
+            } else {
+                output.push('(');
+            }
+
+            for component_type in component_types {
+                push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
+                output.push_str(", ");
+            }
+            if !component_types.is_empty() {
+                output.pop();
+                output.pop();
+            }
+
+            if cpp_like_names {
+                output.push('>');
+            } else {
+                output.push(')');
+            }
+        }
+        ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
+            if !cpp_like_names {
+                output.push('*');
+            }
+            match mutbl {
+                hir::Mutability::Not => output.push_str("const "),
+                hir::Mutability::Mut => output.push_str("mut "),
+            }
+
+            push_debuginfo_type_name(tcx, inner_type, true, output, visited);
+
+            if cpp_like_names {
+                output.push('*');
+            }
+        }
+        ty::Ref(_, inner_type, mutbl) => {
+            if !cpp_like_names {
+                output.push('&');
+            }
+            output.push_str(mutbl.prefix_str());
+
+            push_debuginfo_type_name(tcx, inner_type, true, output, visited);
+
+            if cpp_like_names {
+                output.push('*');
+            }
+        }
+        ty::Array(inner_type, len) => {
+            output.push('[');
+            push_debuginfo_type_name(tcx, inner_type, true, output, visited);
+            output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all())));
+            output.push(']');
+        }
+        ty::Slice(inner_type) => {
+            if cpp_like_names {
+                output.push_str("slice<");
+            } else {
+                output.push('[');
+            }
+
+            push_debuginfo_type_name(tcx, inner_type, true, output, visited);
+
+            if cpp_like_names {
+                output.push('>');
+            } else {
+                output.push(']');
+            }
+        }
+        ty::Dynamic(ref trait_data, ..) => {
+            if let Some(principal) = trait_data.principal() {
+                let principal = tcx
+                    .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &principal);
+                push_item_name(tcx, principal.def_id, false, output);
+                push_type_params(tcx, principal.substs, output, visited);
+            } else {
+                output.push_str("dyn '_");
+            }
+        }
+        ty::FnDef(..) | ty::FnPtr(_) => {
+            // We've encountered a weird 'recursive type'
+            // Currently, the only way to generate such a type
+            // is by using 'impl trait':
+            //
+            // fn foo() -> impl Copy { foo }
+            //
+            // There's not really a sensible name we can generate,
+            // since we don't include 'impl trait' types (e.g. ty::Opaque)
+            // in the output
+            //
+            // Since we need to generate *something*, we just
+            // use a dummy string that should make it clear
+            // that something unusual is going on
+            if !visited.insert(t) {
+                output.push_str("<recursive_type>");
+                return;
+            }
+
+            let sig = t.fn_sig(tcx);
+            output.push_str(sig.unsafety().prefix_str());
+
+            let abi = sig.abi();
+            if abi != rustc_target::spec::abi::Abi::Rust {
+                output.push_str("extern \"");
+                output.push_str(abi.name());
+                output.push_str("\" ");
+            }
+
+            output.push_str("fn(");
+
+            let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+            if !sig.inputs().is_empty() {
+                for &parameter_type in sig.inputs() {
+                    push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
+                    output.push_str(", ");
+                }
+                output.pop();
+                output.pop();
+            }
+
+            if sig.c_variadic {
+                if !sig.inputs().is_empty() {
+                    output.push_str(", ...");
+                } else {
+                    output.push_str("...");
+                }
+            }
+
+            output.push(')');
+
+            if !sig.output().is_unit() {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
+            }
+
+            // We only keep the type in 'visited'
+            // for the duration of the body of this method.
+            // It's fine for a particular function type
+            // to show up multiple times in one overall type
+            // (e.g. MyType<fn() -> u8, fn() -> u8>
+            //
+            // We only care about avoiding recursing
+            // directly back to the type we're currently
+            // processing
+            visited.remove(t);
+        }
+        ty::Closure(def_id, ..) => {
+            output.push_str(&format!(
+                "closure-{}",
+                tcx.def_key(def_id).disambiguated_data.disambiguator
+            ));
+        }
+        ty::Generator(def_id, ..) => {
+            output.push_str(&format!(
+                "generator-{}",
+                tcx.def_key(def_id).disambiguated_data.disambiguator
+            ));
+        }
+        // Type parameters from polymorphized functions.
+        ty::Param(_) => {
+            output.push_str(&format!("{:?}", t));
+        }
+        ty::Error(_)
+        | ty::Infer(_)
+        | ty::Placeholder(..)
+        | ty::Projection(..)
+        | ty::Bound(..)
+        | ty::Opaque(..)
+        | ty::GeneratorWitness(..) => {
+            bug!(
+                "debuginfo: Trying to create type name for \
+                  unexpected type: {:?}",
+                t
+            );
+        }
+    }
+
+    fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
+        if qualified {
+            output.push_str(&tcx.crate_name(def_id.krate).as_str());
+            for path_element in tcx.def_path(def_id).data {
+                output.push_str("::");
+                output.push_str(&path_element.data.as_symbol().as_str());
+            }
+        } else {
+            output.push_str(&tcx.item_name(def_id).as_str());
+        }
+    }
+
+    // Pushes the type parameters in the given `InternalSubsts` to the output string.
+    // This ignores region parameters, since they can't reliably be
+    // reconstructed for items from non-local crates. For local crates, this
+    // would be possible but with inlining and LTO we have to use the least
+    // common denominator - otherwise we would run into conflicts.
+    fn push_type_params<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        substs: SubstsRef<'tcx>,
+        output: &mut String,
+        visited: &mut FxHashSet<Ty<'tcx>>,
+    ) {
+        if substs.types().next().is_none() {
+            return;
+        }
+
+        output.push('<');
+
+        for type_parameter in substs.types() {
+            push_debuginfo_type_name(tcx, type_parameter, true, output, visited);
+            output.push_str(", ");
+        }
+
+        output.pop();
+        output.pop();
+
+        output.push('>');
+    }
+}