diff options
| author | bjorn3 <bjorn3@users.noreply.github.com> | 2019-03-30 15:45:09 +0100 |
|---|---|---|
| committer | bjorn3 <bjorn3@users.noreply.github.com> | 2019-04-20 13:21:40 +0200 |
| commit | d4e7b083ceae25f15f1639cb432d466656aecd77 (patch) | |
| tree | ac5726d882b1196c7ea01d6eeca0331ca643844b /src/librustc_codegen_ssa/debuginfo | |
| parent | dd4566f5118c20889ca778565ba14a065a368dc6 (diff) | |
| download | rust-d4e7b083ceae25f15f1639cb432d466656aecd77.tar.gz rust-d4e7b083ceae25f15f1639cb432d466656aecd77.zip | |
Move cg_llvm/debuginfo/type_names.rs to cg_ssa
Diffstat (limited to 'src/librustc_codegen_ssa/debuginfo')
| -rw-r--r-- | src/librustc_codegen_ssa/debuginfo/mod.rs | 82 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/debuginfo/type_names.rs | 251 |
2 files changed, 333 insertions, 0 deletions
diff --git a/src/librustc_codegen_ssa/debuginfo/mod.rs b/src/librustc_codegen_ssa/debuginfo/mod.rs new file mode 100644 index 00000000000..d60a2e0cb13 --- /dev/null +++ b/src/librustc_codegen_ssa/debuginfo/mod.rs @@ -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() + } +} diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs new file mode 100644 index 00000000000..fee6c5b04d0 --- /dev/null +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -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('>'); + } +} |
