trans: pass essential information from trans_closure to debuginfo.

This commit is contained in:
Eduard Burtescu 2016-04-06 10:49:50 +03:00
parent 35a6e6a02b
commit e945b2852e
4 changed files with 124 additions and 262 deletions

View File

@ -1400,11 +1400,15 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
llfndecl: ValueRef,
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>>)
-> FunctionContext<'blk, 'tcx> {
let (param_substs, def_id) = match instance {
Some(instance) => {
let (param_substs, def_id) = match definition {
Some((instance, _, _, _, _)) => {
common::validate_substs(instance.substs);
(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));
debug!("FunctionContext::new({})",
instance.map_or(String::new(), |i| i.to_string()));
let debug_context = debuginfo::create_function_debug_context(ccx,
inlined_id.unwrap_or(ast::DUMMY_NODE_ID), param_substs, llfndecl);
definition.map_or(String::new(), |d| d.0.to_string()));
let cfg = inlined_id.map(|id| build_cfg(ccx.tcx(), id));
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 default_to_mir = ccx.sess().opts.debugging_opts.orbit;
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))
} else if let Some(def_id) = def_id {
check_attrs(&ccx.sess().cstore.item_attrs(def_id))
@ -1448,6 +1450,18 @@ 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)
} else {
debuginfo::empty_function_debug_context(ccx)
};
FunctionContext {
needs_ret_allocas: nested_returns && mir.is_none(),
mir: mir,
@ -1462,7 +1476,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
fn_ty: fn_ty,
param_substs: param_substs,
span: inlined_id.and_then(|id| ccx.tcx().map.opt_span(id)),
span: span,
block_arena: block_arena,
lpad_arena: TypedArena::new(),
ccx: ccx,
@ -1815,8 +1829,10 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
llfndecl: ValueRef,
instance: Instance<'tcx>,
inlined_id: ast::NodeId,
fn_ty: FnType,
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);
@ -1829,14 +1845,19 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("trans_closure(..., {})", instance);
let fn_ty = FnType::new(ccx, abi, sig, &[]);
let (arena, fcx): (TypedArena<_>, FunctionContext);
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() {
return mir::trans_mir(&fcx);
}
debuginfo::fill_scope_map_for_function(&fcx, decl, body, inlined_id);
// cleanup scope for the incoming arguments
let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(
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.
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.
@ -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));
debug!("trans_fn(param_substs={:?})", param_substs);
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) {
def_id
} 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 = 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,
decl,
body,
llfndecl,
Instance::new(def_id, param_substs),
id,
fn_ty,
&sig,
abi,
&scheme.generics,
Some(ccx.tcx().item_name(def_id)),
closure::ClosureEnv::NotClosure);
}

View File

@ -234,7 +234,10 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
output: sig.output,
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,
decl,
@ -242,8 +245,10 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
llfn,
Instance::new(closure_def_id, param_substs),
id,
fn_ty,
&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

@ -14,8 +14,7 @@ mod doc;
use self::VariableAccess::*;
use self::VariableKind::*;
use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_attribute,
create_DIArray, is_node_local_to_unit};
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
use self::namespace::{namespace_for_item, NamespaceTreeNode};
use self::type_names::compute_debuginfo_type_name;
use self::metadata::{type_metadata, diverging_type_metadata};
@ -25,20 +24,17 @@ use self::source_loc::InternalDebugLocation;
use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
DIDescriptor, FlagPrototyped};
FlagPrototyped};
use rustc::hir::def_id::DefId;
use rustc::infer::normalize_associated_type;
use rustc::ty::subst::{self, Substs};
use rustc::ty::subst::Substs;
use rustc::hir;
use abi::Abi;
use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
use monomorphize;
use rustc::infer;
use monomorphize::Instance;
use rustc::ty::{self, Ty};
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
use rustc::hir::map as hir_map;
use libc::c_uint;
use std::cell::{Cell, RefCell};
@ -49,7 +45,7 @@ use std::rc::Rc;
use syntax::codemap::{Span, Pos};
use syntax::{ast, codemap};
use syntax::attr::IntType;
use syntax::parse::token::{self, special_idents};
use syntax::parse::token;
pub mod gdb;
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.
///
/// 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
/// for the function.
pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
fn_ast_id: ast::NodeId,
param_substs: &Substs<'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;
@ -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.
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
if span == codemap::DUMMY_SP {
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 function_type_metadata = unsafe {
let fn_signature = get_function_signature(cx,
fn_ast_id,
param_substs,
span);
let fn_signature = get_function_signature(cx, sig, abi);
llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
// Get_template_parameters() will append a `<...>` clause to the function
// 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,
generics,
param_substs,
instance.substs,
file_metadata,
&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
// somehow (storing a path in the hir_map, or construct a path using the
// enclosing function).
let (linkage_name, containing_scope) = if has_path {
let fn_ast_def_id = cx.tcx().map.local_def_id(fn_ast_id);
let namespace_node = namespace_for_item(cx, fn_ast_def_id);
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;
@ -368,11 +283,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
(function_name.clone(), file_metadata)
};
// Clang sets this parameter to the opening brace of the function's block,
// so let's do this too.
let scope_line = span_start(cx, top_level_block.span).line;
let scope_line = span_start(cx, 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 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())
};
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)
let fn_debug_context = box FunctionDebugContextData {
scope_map: RefCell::new(scope_map),
scope_map: RefCell::new(NodeMap()),
fn_metadata: fn_metadata,
argument_counter: Cell::new(1),
source_locations_enabled: Cell::new(false),
source_location_override: Cell::new(false),
};
return FunctionDebugContext::RegularContext(fn_debug_context);
fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
fn_ast_id: ast::NodeId,
param_substs: &Substs<'tcx>,
error_reporting_span: Span) -> DIArray {
sig: &ty::FnSig<'tcx>,
abi: Abi) -> DIArray {
if cx.sess().opts.debuginfo == LimitedDebugInfo {
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);
// 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>,
generics: &hir::Generics,
generics: &ty::Generics<'tcx>,
param_substs: &Substs<'tcx>,
file_metadata: DIFile,
name_to_append_suffix_to: &mut String)
-> DIArray
{
let self_type = param_substs.self_ty();
let self_type = normalize_associated_type(cx.tcx(), &self_type);
let actual_types = param_substs.types.as_slice();
// Only true for static default methods:
let has_self_type = self_type.is_some();
if !generics.is_type_parameterized() && !has_self_type {
if actual_types.is_empty() {
return create_DIArray(DIB(cx), &[]);
}
name_to_append_suffix_to.push('<');
// 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];
for (i, &actual_type) in actual_types.iter().enumerate() {
// Add actual type name to <...> clause of function name
let actual_type_name = compute_debuginfo_type_name(cx,
actual_type,
true);
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('>');
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == FullDebugInfo {
// Again, only create type information if full debuginfo is enabled
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 name = CString::new(name.as_str().as_bytes()).unwrap();
let param_metadata = unsafe {
let name = CString::new(param.name.as_str().as_bytes()).unwrap();
unsafe {
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
DIB(cx),
ptr::null_mut(),
@ -565,17 +402,35 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
file_metadata,
0,
0)
};
template_params.push(param_metadata);
}
}
name_to_append_suffix_to.push('>');
}
}).collect()
} else {
vec![]
};
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>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,

View File

@ -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
pub fn span_start(cx: &CrateContext, span: Span) -> codemap::Loc {
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)
-> (DIScope, Span) {
let containing_scope = namespace_for_item(cx, def_id).scope;