Move cg_llvm/debuginfo/type_names.rs to cg_ssa
This commit is contained in:
parent
dd4566f511
commit
d4e7b083ce
4 changed files with 41 additions and 45 deletions
82
src/librustc_codegen_ssa/debuginfo/mod.rs
Normal file
82
src/librustc_codegen_ssa/debuginfo/mod.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use syntax_pos::{BytePos, Span};
|
||||
use rustc::hir::def_id::CrateNum;
|
||||
|
||||
pub mod type_names;
|
||||
|
||||
pub enum FunctionDebugContext<D> {
|
||||
RegularContext(FunctionDebugContextData<D>),
|
||||
DebugInfoDisabled,
|
||||
FunctionWithoutDebugInfo,
|
||||
}
|
||||
|
||||
impl<D> FunctionDebugContext<D> {
|
||||
pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData<D> {
|
||||
match *self {
|
||||
FunctionDebugContext::RegularContext(ref data) => data,
|
||||
FunctionDebugContext::DebugInfoDisabled => {
|
||||
span_bug!(
|
||||
span,
|
||||
"debuginfo: Error trying to access FunctionDebugContext \
|
||||
although debug info is disabled!",
|
||||
);
|
||||
}
|
||||
FunctionDebugContext::FunctionWithoutDebugInfo => {
|
||||
span_bug!(
|
||||
span,
|
||||
"debuginfo: Error trying to access FunctionDebugContext \
|
||||
for function that should be ignored by debug info!",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables emitting source locations for the given functions.
|
||||
///
|
||||
/// Since we don't want source locations to be emitted for the function prelude,
|
||||
/// they are disabled when beginning to codegen a new function. This functions
|
||||
/// switches source location emitting on and must therefore be called before the
|
||||
/// first real statement/expression of the function is codegened.
|
||||
pub fn start_emitting_source_locations<D>(dbg_context: &mut FunctionDebugContext<D>) {
|
||||
match *dbg_context {
|
||||
FunctionDebugContext::RegularContext(ref mut data) => {
|
||||
data.source_locations_enabled = true;
|
||||
},
|
||||
_ => { /* safe to ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionDebugContextData<D> {
|
||||
pub fn_metadata: D,
|
||||
pub source_locations_enabled: bool,
|
||||
pub defining_crate: CrateNum,
|
||||
}
|
||||
|
||||
pub enum VariableAccess<'a, V> {
|
||||
// The llptr given is an alloca containing the variable's value
|
||||
DirectVariable { alloca: V },
|
||||
// The llptr given is an alloca containing the start of some pointer chain
|
||||
// leading to the variable's content.
|
||||
IndirectVariable { alloca: V, address_operations: &'a [i64] }
|
||||
}
|
||||
|
||||
pub enum VariableKind {
|
||||
ArgumentVariable(usize /*index*/),
|
||||
LocalVariable,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MirDebugScope<D> {
|
||||
pub scope_metadata: Option<D>,
|
||||
// Start and end offsets of the file to which this DIScope belongs.
|
||||
// These are used to quickly determine whether some span refers to the same file.
|
||||
pub file_start_pos: BytePos,
|
||||
pub file_end_pos: BytePos,
|
||||
}
|
||||
|
||||
impl<D> MirDebugScope<D> {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
!self.scope_metadata.is_none()
|
||||
}
|
||||
}
|
||||
251
src/librustc_codegen_ssa/debuginfo/type_names.rs
Normal file
251
src/librustc_codegen_ssa/debuginfo/type_names.rs
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
// Type Names for Debug Info.
|
||||
|
||||
use rustc::hir::{self, def_id::DefId};
|
||||
use rustc::ty::{self, Ty, TyCtxt, subst::SubstsRef};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
// 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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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.sty {
|
||||
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.ty_to_string()),
|
||||
ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
|
||||
ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()),
|
||||
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) => {
|
||||
output.push('(');
|
||||
for &component_type in component_types {
|
||||
push_debuginfo_type_name(tcx, component_type, true, output, visited);
|
||||
output.push_str(", ");
|
||||
}
|
||||
if !component_types.is_empty() {
|
||||
output.pop();
|
||||
output.pop();
|
||||
}
|
||||
output.push(')');
|
||||
},
|
||||
ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
|
||||
if !cpp_like_names {
|
||||
output.push('*');
|
||||
}
|
||||
match mutbl {
|
||||
hir::MutImmutable => output.push_str("const "),
|
||||
hir::MutMutable => 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('&');
|
||||
}
|
||||
if mutbl == hir::MutMutable {
|
||||
output.push_str("mut ");
|
||||
}
|
||||
|
||||
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.unwrap_usize(tcx)));
|
||||
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);
|
||||
if sig.unsafety() == hir::Unsafety::Unsafe {
|
||||
output.push_str("unsafe ");
|
||||
}
|
||||
|
||||
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 ¶meter_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(..) => {
|
||||
output.push_str("closure");
|
||||
}
|
||||
ty::Generator(..) => {
|
||||
output.push_str("generator");
|
||||
}
|
||||
ty::Error |
|
||||
ty::Infer(_) |
|
||||
ty::Placeholder(..) |
|
||||
ty::UnnormalizedProjection(..) |
|
||||
ty::Projection(..) |
|
||||
ty::Bound(..) |
|
||||
ty::Opaque(..) |
|
||||
ty::GeneratorWitness(..) |
|
||||
ty::Param(_) => {
|
||||
bug!("debuginfo: Trying to create type name for \
|
||||
unexpected type: {:?}", t);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_item_name(tcx: TyCtxt<'a, 'tcx, '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_interned_str().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<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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('>');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue