mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-15 16:33:49 +00:00
trans: pass essential information from trans_closure to debuginfo.
This commit is contained in:
parent
35a6e6a02b
commit
e945b2852e
@ -1400,11 +1400,15 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
|||||||
pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
|
pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
|
||||||
llfndecl: ValueRef,
|
llfndecl: ValueRef,
|
||||||
fn_ty: FnType,
|
fn_ty: FnType,
|
||||||
instance: Option<Instance<'tcx>>,
|
definition: Option<(Instance<'tcx>,
|
||||||
|
&ty::FnSig<'tcx>,
|
||||||
|
Abi,
|
||||||
|
&ty::Generics<'tcx>,
|
||||||
|
Option<ast::Name>)>,
|
||||||
block_arena: &'blk TypedArena<common::BlockS<'blk, 'tcx>>)
|
block_arena: &'blk TypedArena<common::BlockS<'blk, 'tcx>>)
|
||||||
-> FunctionContext<'blk, 'tcx> {
|
-> FunctionContext<'blk, 'tcx> {
|
||||||
let (param_substs, def_id) = match instance {
|
let (param_substs, def_id) = match definition {
|
||||||
Some(instance) => {
|
Some((instance, _, _, _, _)) => {
|
||||||
common::validate_substs(instance.substs);
|
common::validate_substs(instance.substs);
|
||||||
(instance.substs, Some(instance.def))
|
(instance.substs, Some(instance.def))
|
||||||
}
|
}
|
||||||
@ -1416,10 +1420,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
|||||||
let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
|
let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
|
||||||
|
|
||||||
debug!("FunctionContext::new({})",
|
debug!("FunctionContext::new({})",
|
||||||
instance.map_or(String::new(), |i| i.to_string()));
|
definition.map_or(String::new(), |d| d.0.to_string()));
|
||||||
|
|
||||||
let debug_context = debuginfo::create_function_debug_context(ccx,
|
|
||||||
inlined_id.unwrap_or(ast::DUMMY_NODE_ID), param_substs, llfndecl);
|
|
||||||
|
|
||||||
let cfg = inlined_id.map(|id| build_cfg(ccx.tcx(), id));
|
let cfg = inlined_id.map(|id| build_cfg(ccx.tcx(), id));
|
||||||
let nested_returns = if let Some((blk_id, Some(ref cfg))) = cfg {
|
let nested_returns = if let Some((blk_id, Some(ref cfg))) = cfg {
|
||||||
@ -1431,10 +1432,11 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
|||||||
let check_attrs = |attrs: &[ast::Attribute]| {
|
let check_attrs = |attrs: &[ast::Attribute]| {
|
||||||
let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
|
let default_to_mir = ccx.sess().opts.debugging_opts.orbit;
|
||||||
let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
|
let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" };
|
||||||
default_to_mir ^ attrs.iter().any(|item| item.check_name(invert))
|
(default_to_mir ^ attrs.iter().any(|item| item.check_name(invert)),
|
||||||
|
attrs.iter().any(|item| item.check_name("no_debug")))
|
||||||
};
|
};
|
||||||
|
|
||||||
let use_mir = if let Some(id) = local_id {
|
let (use_mir, no_debug) = if let Some(id) = local_id {
|
||||||
check_attrs(ccx.tcx().map.attrs(id))
|
check_attrs(ccx.tcx().map.attrs(id))
|
||||||
} else if let Some(def_id) = def_id {
|
} else if let Some(def_id) = def_id {
|
||||||
check_attrs(&ccx.sess().cstore.item_attrs(def_id))
|
check_attrs(&ccx.sess().cstore.item_attrs(def_id))
|
||||||
@ -1448,6 +1450,18 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
|||||||
None
|
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)
|
||||||
|
} else {
|
||||||
|
debuginfo::empty_function_debug_context(ccx)
|
||||||
|
};
|
||||||
|
|
||||||
FunctionContext {
|
FunctionContext {
|
||||||
needs_ret_allocas: nested_returns && mir.is_none(),
|
needs_ret_allocas: nested_returns && mir.is_none(),
|
||||||
mir: mir,
|
mir: mir,
|
||||||
@ -1462,7 +1476,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
|||||||
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
|
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
|
||||||
fn_ty: fn_ty,
|
fn_ty: fn_ty,
|
||||||
param_substs: param_substs,
|
param_substs: param_substs,
|
||||||
span: inlined_id.and_then(|id| ccx.tcx().map.opt_span(id)),
|
span: span,
|
||||||
block_arena: block_arena,
|
block_arena: block_arena,
|
||||||
lpad_arena: TypedArena::new(),
|
lpad_arena: TypedArena::new(),
|
||||||
ccx: ccx,
|
ccx: ccx,
|
||||||
@ -1815,8 +1829,10 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
llfndecl: ValueRef,
|
llfndecl: ValueRef,
|
||||||
instance: Instance<'tcx>,
|
instance: Instance<'tcx>,
|
||||||
inlined_id: ast::NodeId,
|
inlined_id: ast::NodeId,
|
||||||
fn_ty: FnType,
|
sig: &ty::FnSig<'tcx>,
|
||||||
abi: Abi,
|
abi: Abi,
|
||||||
|
generics: &ty::Generics<'tcx>,
|
||||||
|
name: Option<ast::Name>,
|
||||||
closure_env: closure::ClosureEnv) {
|
closure_env: closure::ClosureEnv) {
|
||||||
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
|
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
|
||||||
|
|
||||||
@ -1829,14 +1845,19 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
|
|
||||||
debug!("trans_closure(..., {})", instance);
|
debug!("trans_closure(..., {})", instance);
|
||||||
|
|
||||||
|
let fn_ty = FnType::new(ccx, abi, sig, &[]);
|
||||||
|
|
||||||
let (arena, fcx): (TypedArena<_>, FunctionContext);
|
let (arena, fcx): (TypedArena<_>, FunctionContext);
|
||||||
arena = TypedArena::new();
|
arena = TypedArena::new();
|
||||||
fcx = FunctionContext::new(ccx, llfndecl, fn_ty, Some(instance), &arena);
|
fcx = FunctionContext::new(ccx, llfndecl, fn_ty,
|
||||||
|
Some((instance, sig, abi, generics, name)), &arena);
|
||||||
|
|
||||||
if fcx.mir.is_some() {
|
if fcx.mir.is_some() {
|
||||||
return mir::trans_mir(&fcx);
|
return mir::trans_mir(&fcx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debuginfo::fill_scope_map_for_function(&fcx, decl, body, inlined_id);
|
||||||
|
|
||||||
// cleanup scope for the incoming arguments
|
// cleanup scope for the incoming arguments
|
||||||
let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(
|
let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(
|
||||||
ccx, inlined_id, body.span, true);
|
ccx, inlined_id, body.span, true);
|
||||||
@ -1891,10 +1912,8 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret_debug_loc = DebugLoc::At(fn_cleanup_debug_loc.id, fn_cleanup_debug_loc.span);
|
|
||||||
|
|
||||||
// Insert the mandatory first few basic blocks before lltop.
|
// Insert the mandatory first few basic blocks before lltop.
|
||||||
fcx.finish(bcx, ret_debug_loc);
|
fcx.finish(bcx, fn_cleanup_debug_loc.debug_loc());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an LLVM function corresponding to a source language function.
|
/// Creates an LLVM function corresponding to a source language function.
|
||||||
@ -1907,25 +1926,27 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(id));
|
let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(id));
|
||||||
debug!("trans_fn(param_substs={:?})", param_substs);
|
debug!("trans_fn(param_substs={:?})", param_substs);
|
||||||
let _icx = push_ctxt("trans_fn");
|
let _icx = push_ctxt("trans_fn");
|
||||||
let fn_ty = ccx.tcx().node_id_to_type(id);
|
|
||||||
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);
|
|
||||||
let abi = fn_ty.fn_abi();
|
|
||||||
let fn_ty = FnType::new(ccx, abi, &sig, &[]);
|
|
||||||
let def_id = if let Some(&def_id) = ccx.external_srcs().borrow().get(&id) {
|
let def_id = if let Some(&def_id) = ccx.external_srcs().borrow().get(&id) {
|
||||||
def_id
|
def_id
|
||||||
} else {
|
} else {
|
||||||
ccx.tcx().map.local_def_id(id)
|
ccx.tcx().map.local_def_id(id)
|
||||||
};
|
};
|
||||||
|
let scheme = ccx.tcx().lookup_item_type(def_id);
|
||||||
|
let fn_ty = scheme.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);
|
||||||
|
let abi = fn_ty.fn_abi();
|
||||||
trans_closure(ccx,
|
trans_closure(ccx,
|
||||||
decl,
|
decl,
|
||||||
body,
|
body,
|
||||||
llfndecl,
|
llfndecl,
|
||||||
Instance::new(def_id, param_substs),
|
Instance::new(def_id, param_substs),
|
||||||
id,
|
id,
|
||||||
fn_ty,
|
&sig,
|
||||||
abi,
|
abi,
|
||||||
|
&scheme.generics,
|
||||||
|
Some(ccx.tcx().item_name(def_id)),
|
||||||
closure::ClosureEnv::NotClosure);
|
closure::ClosureEnv::NotClosure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +234,10 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
|||||||
output: sig.output,
|
output: sig.output,
|
||||||
variadic: false
|
variadic: false
|
||||||
};
|
};
|
||||||
let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
|
|
||||||
|
// This is not quite right. It should actually inherit
|
||||||
|
// the generics of the enclosing function.
|
||||||
|
let generics = ty::Generics::empty();
|
||||||
|
|
||||||
trans_closure(ccx,
|
trans_closure(ccx,
|
||||||
decl,
|
decl,
|
||||||
@ -242,8 +245,10 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
|||||||
llfn,
|
llfn,
|
||||||
Instance::new(closure_def_id, param_substs),
|
Instance::new(closure_def_id, param_substs),
|
||||||
id,
|
id,
|
||||||
fn_ty,
|
&sig,
|
||||||
Abi::RustCall,
|
Abi::RustCall,
|
||||||
|
&generics,
|
||||||
|
None,
|
||||||
ClosureEnv::Closure(closure_def_id, id));
|
ClosureEnv::Closure(closure_def_id, id));
|
||||||
|
|
||||||
// Don't hoist this to the top of the function. It's perfectly legitimate
|
// Don't hoist this to the top of the function. It's perfectly legitimate
|
||||||
|
@ -14,8 +14,7 @@ mod doc;
|
|||||||
use self::VariableAccess::*;
|
use self::VariableAccess::*;
|
||||||
use self::VariableKind::*;
|
use self::VariableKind::*;
|
||||||
|
|
||||||
use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_attribute,
|
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
|
||||||
create_DIArray, is_node_local_to_unit};
|
|
||||||
use self::namespace::{namespace_for_item, NamespaceTreeNode};
|
use self::namespace::{namespace_for_item, NamespaceTreeNode};
|
||||||
use self::type_names::compute_debuginfo_type_name;
|
use self::type_names::compute_debuginfo_type_name;
|
||||||
use self::metadata::{type_metadata, diverging_type_metadata};
|
use self::metadata::{type_metadata, diverging_type_metadata};
|
||||||
@ -25,20 +24,17 @@ use self::source_loc::InternalDebugLocation;
|
|||||||
use llvm;
|
use llvm;
|
||||||
use llvm::{ModuleRef, ContextRef, ValueRef};
|
use llvm::{ModuleRef, ContextRef, ValueRef};
|
||||||
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
|
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
|
||||||
DIDescriptor, FlagPrototyped};
|
FlagPrototyped};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::normalize_associated_type;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::subst::{self, Substs};
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
|
||||||
use abi::Abi;
|
use abi::Abi;
|
||||||
use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
|
use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
|
||||||
use monomorphize;
|
use monomorphize::Instance;
|
||||||
use rustc::infer;
|
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
|
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
|
||||||
use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
|
use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
|
||||||
use rustc::hir::map as hir_map;
|
|
||||||
|
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@ -49,7 +45,7 @@ use std::rc::Rc;
|
|||||||
use syntax::codemap::{Span, Pos};
|
use syntax::codemap::{Span, Pos};
|
||||||
use syntax::{ast, codemap};
|
use syntax::{ast, codemap};
|
||||||
use syntax::attr::IntType;
|
use syntax::attr::IntType;
|
||||||
use syntax::parse::token::{self, special_idents};
|
use syntax::parse::token;
|
||||||
|
|
||||||
pub mod gdb;
|
pub mod gdb;
|
||||||
mod utils;
|
mod utils;
|
||||||
@ -214,6 +210,18 @@ pub fn finalize(cx: &CrateContext) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a function-specific debug context for a function w/o debuginfo.
|
||||||
|
pub fn empty_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>)
|
||||||
|
-> FunctionDebugContext {
|
||||||
|
if cx.sess().opts.debuginfo == NoDebugInfo {
|
||||||
|
return FunctionDebugContext::DebugInfoDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the debug location so we don't assign them in the function prelude.
|
||||||
|
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
|
||||||
|
FunctionDebugContext::FunctionWithoutDebugInfo
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates the function-specific debug context.
|
/// Creates the function-specific debug context.
|
||||||
///
|
///
|
||||||
/// Returns the FunctionDebugContext for the function which holds state needed
|
/// Returns the FunctionDebugContext for the function which holds state needed
|
||||||
@ -221,8 +229,12 @@ pub fn finalize(cx: &CrateContext) {
|
|||||||
/// FunctionDebugContext enum which indicates why no debuginfo should be created
|
/// FunctionDebugContext enum which indicates why no debuginfo should be created
|
||||||
/// for the function.
|
/// for the function.
|
||||||
pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
fn_ast_id: ast::NodeId,
|
instance: Instance<'tcx>,
|
||||||
param_substs: &Substs<'tcx>,
|
sig: &ty::FnSig<'tcx>,
|
||||||
|
abi: Abi,
|
||||||
|
generics: &ty::Generics<'tcx>,
|
||||||
|
name: Option<ast::Name>,
|
||||||
|
span: Span,
|
||||||
llfn: ValueRef) -> FunctionDebugContext {
|
llfn: ValueRef) -> FunctionDebugContext {
|
||||||
if cx.sess().opts.debuginfo == NoDebugInfo {
|
if cx.sess().opts.debuginfo == NoDebugInfo {
|
||||||
return FunctionDebugContext::DebugInfoDisabled;
|
return FunctionDebugContext::DebugInfoDisabled;
|
||||||
@ -232,102 +244,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
// Do this here already, in case we do an early exit from this function.
|
// Do this here already, in case we do an early exit from this function.
|
||||||
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
|
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
|
||||||
|
|
||||||
if fn_ast_id == ast::DUMMY_NODE_ID {
|
|
||||||
// This is a function not linked to any source location, so don't
|
|
||||||
// generate debuginfo for it.
|
|
||||||
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
let empty_generics = hir::Generics::empty();
|
|
||||||
|
|
||||||
let fnitem = cx.tcx().map.get(fn_ast_id);
|
|
||||||
|
|
||||||
let (name, fn_decl, generics, top_level_block, span, has_path) = match fnitem {
|
|
||||||
hir_map::NodeItem(ref item) => {
|
|
||||||
if contains_nodebug_attribute(&item.attrs) {
|
|
||||||
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
match item.node {
|
|
||||||
hir::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
|
|
||||||
(item.name, fn_decl, generics, top_level_block, item.span, true)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
span_bug!(item.span,
|
|
||||||
"create_function_debug_context: item bound to non-function");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir_map::NodeImplItem(impl_item) => {
|
|
||||||
match impl_item.node {
|
|
||||||
hir::ImplItemKind::Method(ref sig, ref body) => {
|
|
||||||
if contains_nodebug_attribute(&impl_item.attrs) {
|
|
||||||
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
(impl_item.name,
|
|
||||||
&sig.decl,
|
|
||||||
&sig.generics,
|
|
||||||
body,
|
|
||||||
impl_item.span,
|
|
||||||
true)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
span_bug!(impl_item.span,
|
|
||||||
"create_function_debug_context() \
|
|
||||||
called on non-method impl item?!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir_map::NodeExpr(ref expr) => {
|
|
||||||
match expr.node {
|
|
||||||
hir::ExprClosure(_, ref fn_decl, ref top_level_block) => {
|
|
||||||
let name = format!("fn{}", token::gensym("fn"));
|
|
||||||
let name = token::intern(&name[..]);
|
|
||||||
(name, fn_decl,
|
|
||||||
// This is not quite right. It should actually inherit
|
|
||||||
// the generics of the enclosing function.
|
|
||||||
&empty_generics,
|
|
||||||
top_level_block,
|
|
||||||
expr.span,
|
|
||||||
// Don't try to lookup the item path:
|
|
||||||
false)
|
|
||||||
}
|
|
||||||
_ => span_bug!(expr.span,
|
|
||||||
"create_function_debug_context: expected an expr_fn_block here")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir_map::NodeTraitItem(trait_item) => {
|
|
||||||
match trait_item.node {
|
|
||||||
hir::MethodTraitItem(ref sig, Some(ref body)) => {
|
|
||||||
if contains_nodebug_attribute(&trait_item.attrs) {
|
|
||||||
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
(trait_item.name,
|
|
||||||
&sig.decl,
|
|
||||||
&sig.generics,
|
|
||||||
body,
|
|
||||||
trait_item.span,
|
|
||||||
true)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
bug!("create_function_debug_context: \
|
|
||||||
unexpected sort of node: {:?}",
|
|
||||||
fnitem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir_map::NodeForeignItem(..) |
|
|
||||||
hir_map::NodeVariant(..) |
|
|
||||||
hir_map::NodeStructCtor(..) => {
|
|
||||||
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
|
||||||
}
|
|
||||||
_ => bug!("create_function_debug_context: \
|
|
||||||
unexpected sort of node: {:?}",
|
|
||||||
fnitem)
|
|
||||||
};
|
|
||||||
|
|
||||||
// This can be the case for functions inlined from another crate
|
// This can be the case for functions inlined from another crate
|
||||||
if span == codemap::DUMMY_SP {
|
if span == codemap::DUMMY_SP {
|
||||||
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
return FunctionDebugContext::FunctionWithoutDebugInfo;
|
||||||
@ -337,19 +253,19 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
let file_metadata = file_metadata(cx, &loc.file.name);
|
let file_metadata = file_metadata(cx, &loc.file.name);
|
||||||
|
|
||||||
let function_type_metadata = unsafe {
|
let function_type_metadata = unsafe {
|
||||||
let fn_signature = get_function_signature(cx,
|
let fn_signature = get_function_signature(cx, sig, abi);
|
||||||
fn_ast_id,
|
|
||||||
param_substs,
|
|
||||||
span);
|
|
||||||
llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
|
llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get_template_parameters() will append a `<...>` clause to the function
|
// Get_template_parameters() will append a `<...>` clause to the function
|
||||||
// name if necessary.
|
// name if necessary.
|
||||||
let mut function_name = name.to_string();
|
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 template_parameters = get_template_parameters(cx,
|
let template_parameters = get_template_parameters(cx,
|
||||||
generics,
|
generics,
|
||||||
param_substs,
|
instance.substs,
|
||||||
file_metadata,
|
file_metadata,
|
||||||
&mut function_name);
|
&mut function_name);
|
||||||
|
|
||||||
@ -357,9 +273,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
// just don't put them into a namespace. In the future this could be improved
|
// 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
|
// somehow (storing a path in the hir_map, or construct a path using the
|
||||||
// enclosing function).
|
// enclosing function).
|
||||||
let (linkage_name, containing_scope) = if has_path {
|
let (linkage_name, containing_scope) = if name.is_some() {
|
||||||
let fn_ast_def_id = cx.tcx().map.local_def_id(fn_ast_id);
|
let namespace_node = namespace_for_item(cx, instance.def);
|
||||||
let namespace_node = namespace_for_item(cx, fn_ast_def_id);
|
|
||||||
let linkage_name = namespace_node.mangled_name_of_contained_item(
|
let linkage_name = namespace_node.mangled_name_of_contained_item(
|
||||||
&function_name[..]);
|
&function_name[..]);
|
||||||
let containing_scope = namespace_node.scope;
|
let containing_scope = namespace_node.scope;
|
||||||
@ -368,11 +283,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
(function_name.clone(), file_metadata)
|
(function_name.clone(), file_metadata)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clang sets this parameter to the opening brace of the function's block,
|
let scope_line = span_start(cx, span).line;
|
||||||
// so let's do this too.
|
|
||||||
let scope_line = span_start(cx, top_level_block.span).line;
|
|
||||||
|
|
||||||
let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
|
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(function_name).unwrap();
|
||||||
let linkage_name = CString::new(linkage_name).unwrap();
|
let linkage_name = CString::new(linkage_name).unwrap();
|
||||||
@ -395,54 +309,24 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
ptr::null_mut())
|
ptr::null_mut())
|
||||||
};
|
};
|
||||||
|
|
||||||
let scope_map = create_scope_map::create_scope_map(cx,
|
|
||||||
&fn_decl.inputs,
|
|
||||||
&top_level_block,
|
|
||||||
fn_metadata,
|
|
||||||
fn_ast_id);
|
|
||||||
|
|
||||||
// Initialize fn debug context (including scope map and namespace map)
|
// Initialize fn debug context (including scope map and namespace map)
|
||||||
let fn_debug_context = box FunctionDebugContextData {
|
let fn_debug_context = box FunctionDebugContextData {
|
||||||
scope_map: RefCell::new(scope_map),
|
scope_map: RefCell::new(NodeMap()),
|
||||||
fn_metadata: fn_metadata,
|
fn_metadata: fn_metadata,
|
||||||
argument_counter: Cell::new(1),
|
argument_counter: Cell::new(1),
|
||||||
source_locations_enabled: Cell::new(false),
|
source_locations_enabled: Cell::new(false),
|
||||||
source_location_override: Cell::new(false),
|
source_location_override: Cell::new(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return FunctionDebugContext::RegularContext(fn_debug_context);
|
return FunctionDebugContext::RegularContext(fn_debug_context);
|
||||||
|
|
||||||
fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
fn_ast_id: ast::NodeId,
|
sig: &ty::FnSig<'tcx>,
|
||||||
param_substs: &Substs<'tcx>,
|
abi: Abi) -> DIArray {
|
||||||
error_reporting_span: Span) -> DIArray {
|
|
||||||
if cx.sess().opts.debuginfo == LimitedDebugInfo {
|
if cx.sess().opts.debuginfo == LimitedDebugInfo {
|
||||||
return create_DIArray(DIB(cx), &[]);
|
return create_DIArray(DIB(cx), &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return type -- llvm::DIBuilder wants this at index 0
|
|
||||||
assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
|
|
||||||
let fn_type = cx.tcx().node_id_to_type(fn_ast_id);
|
|
||||||
let fn_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &fn_type);
|
|
||||||
|
|
||||||
let (sig, abi) = match fn_type.sty {
|
|
||||||
ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => {
|
|
||||||
let sig = cx.tcx().erase_late_bound_regions(&barefnty.sig);
|
|
||||||
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
|
|
||||||
(sig, barefnty.abi)
|
|
||||||
}
|
|
||||||
ty::TyClosure(def_id, ref substs) => {
|
|
||||||
let closure_type = cx.tcx().closure_type(def_id, substs);
|
|
||||||
let sig = cx.tcx().erase_late_bound_regions(&closure_type.sig);
|
|
||||||
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
|
|
||||||
(sig, closure_type.abi)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => bug!("get_function_metdata: Expected a function type!")
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut signature = Vec::with_capacity(sig.inputs.len() + 1);
|
let mut signature = Vec::with_capacity(sig.inputs.len() + 1);
|
||||||
|
|
||||||
// Return type -- llvm::DIBuilder wants this at index 0
|
// Return type -- llvm::DIBuilder wants this at index 0
|
||||||
@ -477,86 +361,39 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||||
generics: &hir::Generics,
|
generics: &ty::Generics<'tcx>,
|
||||||
param_substs: &Substs<'tcx>,
|
param_substs: &Substs<'tcx>,
|
||||||
file_metadata: DIFile,
|
file_metadata: DIFile,
|
||||||
name_to_append_suffix_to: &mut String)
|
name_to_append_suffix_to: &mut String)
|
||||||
-> DIArray
|
-> DIArray
|
||||||
{
|
{
|
||||||
let self_type = param_substs.self_ty();
|
let actual_types = param_substs.types.as_slice();
|
||||||
let self_type = normalize_associated_type(cx.tcx(), &self_type);
|
|
||||||
|
|
||||||
// Only true for static default methods:
|
if actual_types.is_empty() {
|
||||||
let has_self_type = self_type.is_some();
|
|
||||||
|
|
||||||
if !generics.is_type_parameterized() && !has_self_type {
|
|
||||||
return create_DIArray(DIB(cx), &[]);
|
return create_DIArray(DIB(cx), &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
name_to_append_suffix_to.push('<');
|
name_to_append_suffix_to.push('<');
|
||||||
|
for (i, &actual_type) in actual_types.iter().enumerate() {
|
||||||
// The list to be filled with template parameters:
|
|
||||||
let mut template_params: Vec<DIDescriptor> =
|
|
||||||
Vec::with_capacity(generics.ty_params.len() + 1);
|
|
||||||
|
|
||||||
// Handle self type
|
|
||||||
if has_self_type {
|
|
||||||
let actual_self_type = self_type.unwrap();
|
|
||||||
// Add self type name to <...> clause of function name
|
|
||||||
let actual_self_type_name = compute_debuginfo_type_name(
|
|
||||||
cx,
|
|
||||||
actual_self_type,
|
|
||||||
true);
|
|
||||||
|
|
||||||
name_to_append_suffix_to.push_str(&actual_self_type_name[..]);
|
|
||||||
|
|
||||||
if generics.is_type_parameterized() {
|
|
||||||
name_to_append_suffix_to.push_str(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only create type information if full debuginfo is enabled
|
|
||||||
if cx.sess().opts.debuginfo == FullDebugInfo {
|
|
||||||
let actual_self_type_metadata = type_metadata(cx,
|
|
||||||
actual_self_type,
|
|
||||||
codemap::DUMMY_SP);
|
|
||||||
|
|
||||||
let name = special_idents::type_self.name.as_str();
|
|
||||||
|
|
||||||
let name = CString::new(name.as_bytes()).unwrap();
|
|
||||||
let param_metadata = unsafe {
|
|
||||||
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
|
||||||
DIB(cx),
|
|
||||||
ptr::null_mut(),
|
|
||||||
name.as_ptr(),
|
|
||||||
actual_self_type_metadata,
|
|
||||||
file_metadata,
|
|
||||||
0,
|
|
||||||
0)
|
|
||||||
};
|
|
||||||
|
|
||||||
template_params.push(param_metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle other generic parameters
|
|
||||||
let actual_types = param_substs.types.get_slice(subst::FnSpace);
|
|
||||||
for (index, &hir::TyParam{ name, .. }) in generics.ty_params.iter().enumerate() {
|
|
||||||
let actual_type = actual_types[index];
|
|
||||||
// Add actual type name to <...> clause of function name
|
// Add actual type name to <...> clause of function name
|
||||||
let actual_type_name = compute_debuginfo_type_name(cx,
|
let actual_type_name = compute_debuginfo_type_name(cx,
|
||||||
actual_type,
|
actual_type,
|
||||||
true);
|
true);
|
||||||
name_to_append_suffix_to.push_str(&actual_type_name[..]);
|
name_to_append_suffix_to.push_str(&actual_type_name[..]);
|
||||||
|
|
||||||
if index != generics.ty_params.len() - 1 {
|
if i != actual_types.len() - 1 {
|
||||||
name_to_append_suffix_to.push_str(",");
|
name_to_append_suffix_to.push_str(",");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
name_to_append_suffix_to.push('>');
|
||||||
|
|
||||||
// Again, only create type information if full debuginfo is enabled
|
// Again, only create type information if full debuginfo is enabled
|
||||||
if cx.sess().opts.debuginfo == FullDebugInfo {
|
let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
|
||||||
|
generics.types.as_slice().iter().enumerate().map(|(i, param)| {
|
||||||
|
let actual_type = actual_types[i];
|
||||||
let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
|
let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
|
||||||
let name = CString::new(name.as_str().as_bytes()).unwrap();
|
let name = CString::new(param.name.as_str().as_bytes()).unwrap();
|
||||||
let param_metadata = unsafe {
|
unsafe {
|
||||||
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
@ -565,17 +402,35 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
file_metadata,
|
file_metadata,
|
||||||
0,
|
0,
|
||||||
0)
|
0)
|
||||||
};
|
}
|
||||||
template_params.push(param_metadata);
|
}).collect()
|
||||||
}
|
} else {
|
||||||
}
|
vec![]
|
||||||
|
};
|
||||||
name_to_append_suffix_to.push('>');
|
|
||||||
|
|
||||||
return create_DIArray(DIB(cx), &template_params[..]);
|
return create_DIArray(DIB(cx), &template_params[..]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the scope map for a function given its declaration and body.
|
||||||
|
pub fn fill_scope_map_for_function<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
|
||||||
|
fn_decl: &hir::FnDecl,
|
||||||
|
top_level_block: &hir::Block,
|
||||||
|
fn_ast_id: ast::NodeId) {
|
||||||
|
match fcx.debug_context {
|
||||||
|
FunctionDebugContext::RegularContext(box ref data) => {
|
||||||
|
let scope_map = create_scope_map::create_scope_map(fcx.ccx,
|
||||||
|
&fn_decl.inputs,
|
||||||
|
top_level_block,
|
||||||
|
data.fn_metadata,
|
||||||
|
fn_ast_id);
|
||||||
|
*data.scope_map.borrow_mut() = scope_map;
|
||||||
|
}
|
||||||
|
FunctionDebugContext::DebugInfoDisabled |
|
||||||
|
FunctionDebugContext::FunctionWithoutDebugInfo => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
variable_name: ast::Name,
|
variable_name: ast::Name,
|
||||||
variable_type: Ty<'tcx>,
|
variable_type: Ty<'tcx>,
|
||||||
|
@ -44,16 +44,6 @@ pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_nodebug_attribute(attributes: &[ast::Attribute]) -> bool {
|
|
||||||
attributes.iter().any(|attr| {
|
|
||||||
let meta_item: &ast::MetaItem = &attr.node.value;
|
|
||||||
match meta_item.node {
|
|
||||||
ast::MetaItemKind::Word(ref value) => &value[..] == "no_debug",
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return codemap::Loc corresponding to the beginning of the span
|
/// Return codemap::Loc corresponding to the beginning of the span
|
||||||
pub fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
|
pub fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
|
||||||
cx.sess().codemap().lookup_char_pos(span.lo)
|
cx.sess().codemap().lookup_char_pos(span.lo)
|
||||||
@ -87,15 +77,6 @@ pub fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert_type_for_node_id(cx: &CrateContext,
|
|
||||||
node_id: ast::NodeId,
|
|
||||||
error_reporting_span: Span) {
|
|
||||||
if !cx.tcx().node_types().contains_key(&node_id) {
|
|
||||||
span_bug!(error_reporting_span,
|
|
||||||
"debuginfo: Could not find type for node id!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
|
pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
|
||||||
-> (DIScope, Span) {
|
-> (DIScope, Span) {
|
||||||
let containing_scope = namespace_for_item(cx, def_id).scope;
|
let containing_scope = namespace_for_item(cx, def_id).scope;
|
||||||
|
Loading…
Reference in New Issue
Block a user