trans: use DefKey directly in debuginfo for paths.

This commit is contained in:
Eduard Burtescu 2016-04-06 15:37:19 +03:00
parent e945b2852e
commit 4e6b178649
6 changed files with 112 additions and 192 deletions

View File

@ -1400,15 +1400,11 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
llfndecl: ValueRef,
fn_ty: FnType,
definition: Option<(Instance<'tcx>,
&ty::FnSig<'tcx>,
Abi,
&ty::Generics<'tcx>,
Option<ast::Name>)>,
definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi)>,
block_arena: &'blk TypedArena<common::BlockS<'blk, 'tcx>>)
-> FunctionContext<'blk, 'tcx> {
let (param_substs, def_id) = match definition {
Some((instance, _, _, _, _)) => {
Some((instance, _, _)) => {
common::validate_substs(instance.substs);
(instance.substs, Some(instance.def))
}
@ -1450,14 +1446,9 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
None
};
let span = inlined_id.and_then(|id| ccx.tcx().map.opt_span(id));
let debug_context = if let (false, Some(definition)) = (no_debug, definition) {
let (instance, sig, abi, generics, name) = definition;
debuginfo::create_function_debug_context(ccx, instance, sig,
abi, generics, name,
span.unwrap_or(DUMMY_SP),
llfndecl)
let (instance, sig, abi) = definition;
debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl)
} else {
debuginfo::empty_function_debug_context(ccx)
};
@ -1476,7 +1467,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
fn_ty: fn_ty,
param_substs: param_substs,
span: span,
span: inlined_id.and_then(|id| ccx.tcx().map.opt_span(id)),
block_arena: block_arena,
lpad_arena: TypedArena::new(),
ccx: ccx,
@ -1831,8 +1822,6 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
inlined_id: ast::NodeId,
sig: &ty::FnSig<'tcx>,
abi: Abi,
generics: &ty::Generics<'tcx>,
name: Option<ast::Name>,
closure_env: closure::ClosureEnv) {
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
@ -1849,8 +1838,7 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let (arena, fcx): (TypedArena<_>, FunctionContext);
arena = TypedArena::new();
fcx = FunctionContext::new(ccx, llfndecl, fn_ty,
Some((instance, sig, abi, generics, name)), &arena);
fcx = FunctionContext::new(ccx, llfndecl, fn_ty, Some((instance, sig, abi)), &arena);
if fcx.mir.is_some() {
return mir::trans_mir(&fcx);
@ -1931,8 +1919,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
} else {
ccx.tcx().map.local_def_id(id)
};
let scheme = ccx.tcx().lookup_item_type(def_id);
let fn_ty = scheme.ty;
let fn_ty = ccx.tcx().lookup_item_type(def_id).ty;
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fn_ty);
let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
@ -1945,8 +1932,6 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
id,
&sig,
abi,
&scheme.generics,
Some(ccx.tcx().item_name(def_id)),
closure::ClosureEnv::NotClosure);
}

View File

@ -235,10 +235,6 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
variadic: false
};
// This is not quite right. It should actually inherit
// the generics of the enclosing function.
let generics = ty::Generics::empty();
trans_closure(ccx,
decl,
body,
@ -247,8 +243,6 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
id,
&sig,
Abi::RustCall,
&generics,
None,
ClosureEnv::Closure(closure_def_id, id));
// Don't hoist this to the top of the function. It's perfectly legitimate

View File

@ -16,7 +16,7 @@ use self::EnumDiscriminantInfo::*;
use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align_of,
get_namespace_and_span_for_item, create_DIArray,
fn_should_be_ignored, is_node_local_to_unit};
use super::namespace::namespace_for_item;
use super::namespace::mangled_name_of_item;
use super::type_names::{compute_debuginfo_type_name, push_debuginfo_type_name};
use super::{declare_local, VariableKind, VariableAccess};
@ -68,8 +68,8 @@ pub const UNKNOWN_LINE_NUMBER: c_uint = 0;
pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
// ptr::null() doesn't work :(
const NO_FILE_METADATA: DIFile = (0 as DIFile);
const NO_SCOPE_METADATA: DIScope = (0 as DIScope);
pub const NO_FILE_METADATA: DIFile = (0 as DIFile);
pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope);
const FLAGS_NONE: c_uint = 0;
@ -1846,28 +1846,8 @@ pub fn create_global_var_metadata(cx: &CrateContext,
return;
}
let var_item = cx.tcx().map.get(node_id);
let (name, span) = match var_item {
hir_map::NodeItem(item) => {
match item.node {
hir::ItemStatic(..) => (item.name, item.span),
hir::ItemConst(..) => (item.name, item.span),
_ => {
span_bug!(item.span,
"debuginfo::\
create_global_var_metadata() -
Captured var-id refers to \
unexpected ast_item variant: {:?}",
var_item)
}
}
},
_ => bug!("debuginfo::create_global_var_metadata() \
- Captured var-id refers to unexpected \
hir_map variant: {:?}",
var_item)
};
let node_def_id = cx.tcx().map.local_def_id(node_id);
let (var_scope, span) = get_namespace_and_span_for_item(cx, node_def_id);
let (file_metadata, line_number) = if span != codemap::DUMMY_SP {
let loc = span_start(cx, span);
@ -1879,12 +1859,8 @@ pub fn create_global_var_metadata(cx: &CrateContext,
let is_local_to_unit = is_node_local_to_unit(cx, node_id);
let variable_type = cx.tcx().node_id_to_type(node_id);
let type_metadata = type_metadata(cx, variable_type, span);
let node_def_id = cx.tcx().map.local_def_id(node_id);
let namespace_node = namespace_for_item(cx, node_def_id);
let var_name = name.to_string();
let linkage_name =
namespace_node.mangled_name_of_contained_item(&var_name[..]);
let var_scope = namespace_node.scope;
let var_name = cx.tcx().item_name(node_def_id).to_string();
let linkage_name = mangled_name_of_item(cx, node_def_id, "");
let var_name = CString::new(var_name).unwrap();
let linkage_name = CString::new(linkage_name).unwrap();

View File

@ -14,8 +14,9 @@ mod doc;
use self::VariableAccess::*;
use self::VariableKind::*;
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
use self::namespace::{namespace_for_item, NamespaceTreeNode};
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit,
get_namespace_and_span_for_item};
use self::namespace::mangled_name_of_item;
use self::type_names::compute_debuginfo_type_name;
use self::metadata::{type_metadata, diverging_type_metadata};
use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata};
@ -26,6 +27,7 @@ use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
FlagPrototyped};
use rustc::hir::def_id::DefId;
use rustc::hir::map::DefPathData;
use rustc::ty::subst::Substs;
use rustc::hir;
@ -34,18 +36,16 @@ use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
use monomorphize::Instance;
use rustc::ty::{self, Ty};
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet};
use libc::c_uint;
use std::cell::{Cell, RefCell};
use std::ffi::CString;
use std::ptr;
use std::rc::Rc;
use syntax::codemap::{Span, Pos};
use syntax::{ast, codemap};
use syntax::attr::IntType;
use syntax::parse::token;
pub mod gdb;
mod utils;
@ -80,7 +80,7 @@ pub struct CrateDebugContext<'tcx> {
created_enum_disr_types: RefCell<FnvHashMap<(DefId, IntType), DIType>>,
type_map: RefCell<TypeMap<'tcx>>,
namespace_map: RefCell<FnvHashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
namespace_map: RefCell<DefIdMap<DIScope>>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
@ -100,7 +100,7 @@ impl<'tcx> CrateDebugContext<'tcx> {
created_files: RefCell::new(FnvHashMap()),
created_enum_disr_types: RefCell::new(FnvHashMap()),
type_map: RefCell::new(TypeMap::new()),
namespace_map: RefCell::new(FnvHashMap()),
namespace_map: RefCell::new(DefIdMap()),
composite_types_completed: RefCell::new(FnvHashSet()),
};
}
@ -232,9 +232,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
sig: &ty::FnSig<'tcx>,
abi: Abi,
generics: &ty::Generics<'tcx>,
name: Option<ast::Name>,
span: Span,
llfn: ValueRef) -> FunctionDebugContext {
if cx.sess().opts.debuginfo == NoDebugInfo {
return FunctionDebugContext::DebugInfoDisabled;
@ -245,6 +242,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
// This can be the case for functions inlined from another crate
let (containing_scope, span) = get_namespace_and_span_for_item(cx, instance.def);
if span == codemap::DUMMY_SP {
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
@ -257,38 +255,34 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
// Find the enclosing function, in case this is a closure.
let mut fn_def_id = instance.def;
let mut def_key = cx.tcx().def_key(fn_def_id);
let mut name = def_key.disambiguated_data.data.to_string();
let name_len = name.len();
while def_key.disambiguated_data.data == DefPathData::ClosureExpr {
fn_def_id.index = def_key.parent.expect("closure without a parent?");
def_key = cx.tcx().def_key(fn_def_id);
}
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
let mut function_name = name.map(|name| name.to_string()).unwrap_or_else(|| {
// We do this only for closures atm.
format!("fn{}", token::gensym("fn"))
});
let generics = cx.tcx().lookup_item_type(fn_def_id).generics;
let template_parameters = get_template_parameters(cx,
generics,
&generics,
instance.substs,
file_metadata,
&mut function_name);
&mut name);
// There is no hir_map::Path for hir::ExprClosure-type functions. For now,
// just don't put them into a namespace. In the future this could be improved
// somehow (storing a path in the hir_map, or construct a path using the
// enclosing function).
let (linkage_name, containing_scope) = if name.is_some() {
let namespace_node = namespace_for_item(cx, instance.def);
let linkage_name = namespace_node.mangled_name_of_contained_item(
&function_name[..]);
let containing_scope = namespace_node.scope;
(linkage_name, containing_scope)
} else {
(function_name.clone(), file_metadata)
};
// Build the linkage_name out of the item path and "template" parameters.
let linkage_name = mangled_name_of_item(cx, instance.def, &name[name_len..]);
let scope_line = span_start(cx, span).line;
let local_id = cx.tcx().map.as_local_node_id(instance.def);
let is_local_to_unit = local_id.map_or(false, |id| is_node_local_to_unit(cx, id));
let function_name = CString::new(function_name).unwrap();
let function_name = CString::new(name).unwrap();
let linkage_name = CString::new(linkage_name).unwrap();
let fn_metadata = unsafe {
llvm::LLVMDIBuilderCreateFunction(

View File

@ -10,118 +10,82 @@
// Namespace Handling.
use super::utils::{DIB, debug_context};
use super::metadata::{file_metadata, NO_FILE_METADATA, UNKNOWN_LINE_NUMBER};
use super::utils::{DIB, debug_context, span_start};
use llvm;
use llvm::debuginfo::DIScope;
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
use rustc::hir::map::DefPathData;
use common::CrateContext;
use libc::c_uint;
use std::ffi::CString;
use std::iter::once;
use std::ptr;
use std::rc::{Rc, Weak};
use syntax::ast;
use syntax::parse::token;
use syntax::codemap::DUMMY_SP;
pub struct NamespaceTreeNode {
pub name: ast::Name,
pub scope: DIScope,
pub parent: Option<Weak<NamespaceTreeNode>>,
}
impl NamespaceTreeNode {
pub fn mangled_name_of_contained_item(&self, item_name: &str) -> String {
fn fill_nested(node: &NamespaceTreeNode, output: &mut String) {
match node.parent {
Some(ref parent) => fill_nested(&parent.upgrade().unwrap(), output),
None => {}
}
let string = node.name.as_str();
output.push_str(&string.len().to_string());
output.push_str(&string);
pub fn mangled_name_of_item(ccx: &CrateContext, def_id: DefId, extra: &str) -> String {
fn fill_nested(ccx: &CrateContext, def_id: DefId, extra: &str, output: &mut String) {
let def_key = ccx.tcx().def_key(def_id);
if let Some(parent) = def_key.parent {
fill_nested(ccx, DefId {
krate: def_id.krate,
index: parent
}, "", output);
}
let mut name = String::from("_ZN");
fill_nested(self, &mut name);
name.push_str(&item_name.len().to_string());
name.push_str(item_name);
name.push('E');
name
}
}
pub fn namespace_for_item(cx: &CrateContext, def_id: DefId) -> Rc<NamespaceTreeNode> {
// prepend crate name.
// This shouldn't need a roundtrip through InternedString.
let krate = token::intern(&cx.tcx().crate_name(def_id.krate));
let krate = hir_map::DefPathData::TypeNs(krate);
let path = cx.tcx().def_path(def_id).data;
let mut path = once(krate).chain(path.into_iter().map(|e| e.data)).peekable();
let mut current_key = Vec::new();
let mut parent_node: Option<Rc<NamespaceTreeNode>> = None;
// Create/Lookup namespace for each element of the path.
loop {
// Emulate a for loop so we can use peek below.
let path_element = match path.next() {
Some(e) => e,
None => break
};
// Ignore the name of the item (the last path element).
if path.peek().is_none() {
break;
}
// This shouldn't need a roundtrip through InternedString.
let namespace_name = path_element.as_interned_str();
let name = token::intern(&namespace_name);
current_key.push(name);
let existing_node = debug_context(cx).namespace_map.borrow()
.get(&current_key).cloned();
let current_node = match existing_node {
Some(existing_node) => existing_node,
None => {
// create and insert
let parent_scope = match parent_node {
Some(ref node) => node.scope,
None => ptr::null_mut()
};
let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
let scope = unsafe {
llvm::LLVMDIBuilderCreateNameSpace(
DIB(cx),
parent_scope,
namespace_name.as_ptr(),
// cannot reconstruct file ...
ptr::null_mut(),
// ... or line information, but that's not so important.
0)
};
let node = Rc::new(NamespaceTreeNode {
name: name,
scope: scope,
parent: parent_node.map(|parent| Rc::downgrade(&parent)),
});
debug_context(cx).namespace_map.borrow_mut()
.insert(current_key.clone(), node.clone());
node
}
let name = match def_key.disambiguated_data.data {
DefPathData::CrateRoot => ccx.tcx().crate_name(def_id.krate),
data => data.as_interned_str()
};
parent_node = Some(current_node);
output.push_str(&(name.len() + extra.len()).to_string());
output.push_str(&name);
output.push_str(extra);
}
match parent_node {
Some(node) => node,
None => {
bug!("debuginfo::namespace_for_item: path too short for {:?}", def_id);
}
}
let mut name = String::from("_ZN");
fill_nested(ccx, def_id, extra, &mut name);
name.push('E');
name
}
pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope {
if let Some(&scope) = debug_context(ccx).namespace_map.borrow().get(&def_id) {
return scope;
}
let def_key = ccx.tcx().def_key(def_id);
let parent_scope = def_key.parent.map_or(ptr::null_mut(), |parent| {
item_namespace(ccx, DefId {
krate: def_id.krate,
index: parent
})
});
let namespace_name = match def_key.disambiguated_data.data {
DefPathData::CrateRoot => ccx.tcx().crate_name(def_id.krate),
data => data.as_interned_str()
};
let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
let span = ccx.tcx().map.def_id_span(def_id, DUMMY_SP);
let (file, line) = if span != DUMMY_SP {
let loc = span_start(ccx, span);
(file_metadata(ccx, &loc.file.name), loc.line as c_uint)
} else {
(NO_FILE_METADATA, UNKNOWN_LINE_NUMBER)
};
let scope = unsafe {
llvm::LLVMDIBuilderCreateNameSpace(
DIB(ccx),
parent_scope,
namespace_name.as_ptr(),
file,
line as c_uint)
};
debug_context(ccx).namespace_map.borrow_mut().insert(def_id, scope);
scope
}

View File

@ -11,7 +11,7 @@
// Utility Functions.
use super::{FunctionDebugContext, CrateDebugContext};
use super::namespace::namespace_for_item;
use super::namespace::item_namespace;
use rustc::hir::def_id::DefId;
@ -79,10 +79,17 @@ pub fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
-> (DIScope, Span) {
let containing_scope = namespace_for_item(cx, def_id).scope;
let definition_span = cx.tcx().map.def_id_span(def_id, codemap::DUMMY_SP /* (1) */ );
let containing_scope = item_namespace(cx, DefId {
krate: def_id.krate,
index: cx.tcx().def_key(def_id).parent
.expect("get_namespace_and_span_for_item: missing parent?")
});
// (1) For external items there is no span information
// Try to get some span information, if we have an inlined item.
let definition_span = match cx.external().borrow().get(&def_id) {
Some(&Some(node_id)) => cx.tcx().map.span(node_id),
_ => cx.tcx().map.def_id_span(def_id, codemap::DUMMY_SP)
};
(containing_scope, definition_span)
}