let fcx = FunctionContext::new(ccx, lldecl, fn_ty, Some((instance, &sig, abi)), true);
let mir = ccx.tcx().item_mir(instance.def);
- mir::trans_mir(&fcx, &mir);
+ mir::trans_mir(&fcx, &mir, instance, &sig, abi);
}
pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
use llvm;
use llvm::{ValueRef, BasicBlockRef, ContextRef, TypeKind};
use llvm::{True, False, Bool, OperandBundleDef, get_param};
-use llvm::debuginfo::DIScope;
use monomorphize::Instance;
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use builder::Builder;
use callee::Callee;
use consts;
-use debuginfo;
use declare;
use machine;
use monomorphize;
// This function's enclosing crate context.
pub ccx: &'a CrateContext<'a, 'tcx>,
- // Used and maintained by the debuginfo module.
- pub debug_context: debuginfo::FunctionDebugContext,
-
alloca_builder: Builder<'a, 'tcx>,
}
definition: Option<(Instance<'tcx>, &ty::FnSig<'tcx>, Abi)>,
skip_retptr: bool,
) -> FunctionContext<'a, 'tcx> {
- let (param_substs, def_id) = match definition {
+ let param_substs = match definition {
Some((instance, ..)) => {
assert!(!instance.substs.needs_infer());
- (instance.substs, Some(instance.def))
+ instance.substs
}
- None => (ccx.tcx().intern_substs(&[]), None)
- };
-
- let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
-
- debug!("FunctionContext::new({})", definition.map_or(String::new(), |d| d.0.to_string()));
-
- let no_debug = if let Some(id) = local_id {
- ccx.tcx().map.attrs(id).iter().any(|item| item.check_name("no_debug"))
- } else if let Some(def_id) = def_id {
- ccx.sess().cstore.item_attrs(def_id).iter().any(|item| item.check_name("no_debug"))
- } else {
- false
- };
-
- let mir = def_id.map(|id| ccx.tcx().item_mir(id));
-
- let debug_context = if let (false, Some((instance, sig, abi)), &Some(ref mir)) =
- (no_debug, definition, &mir) {
- debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfndecl, mir)
- } else {
- debuginfo::empty_function_debug_context(ccx)
+ None => ccx.tcx().intern_substs(&[])
};
let mut fcx = FunctionContext {
fn_ty: fn_ty,
param_substs: param_substs,
ccx: ccx,
- debug_context: debug_context,
alloca_builder: Builder::with_ccx(ccx),
};
}
}
- pub fn set_source_location(&self, scope: DIScope, sp: Span) {
- debuginfo::set_source_location(self.fcx(), self, scope, sp)
- }
-
pub fn at_start<F, R>(&self, f: F) -> R
where F: FnOnce(&BlockAndBuilder<'a, 'tcx>) -> R
{
/// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
/// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(fcx: &FunctionContext, mir: &Mir)
+pub fn create_mir_scopes(fcx: &FunctionContext, mir: &Mir, debug_context: &FunctionDebugContext)
-> IndexVec<VisibilityScope, MirDebugScope> {
let null_scope = MirDebugScope {
scope_metadata: ptr::null_mut(),
};
let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
- let fn_metadata = match fcx.debug_context {
+ let fn_metadata = match *debug_context {
FunctionDebugContext::RegularContext(ref data) => data.fn_metadata,
FunctionDebugContext::DebugInfoDisabled |
FunctionDebugContext::FunctionWithoutDebugInfo => {
use abi::Abi;
use common::{CrateContext, BlockAndBuilder};
+use mir::MirContext;
use monomorphize::{self, Instance};
use rustc::ty::{self, Ty};
use rustc::mir;
// This can be the case for functions inlined from another crate
if span == syntax_pos::DUMMY_SP {
+ // FIXME(simulacrum): Probably can't happen; remove.
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
}
pub fn declare_local<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
+ mir: &MirContext,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: DIScope,
match variable_kind {
ArgumentVariable(_) | CapturedVariable => {
- assert!(!bcx.fcx().debug_context.get_ref(span).source_locations_enabled.get());
+ assert!(!mir.debug_context.get_ref(span).source_locations_enabled.get());
source_loc::set_debug_location(cx, bcx, UnknownLocation);
}
_ => { /* nothing to do */ }
use llvm;
use llvm::debuginfo::DIScope;
use builder::Builder;
-use common::{CrateContext, FunctionContext};
+use common::CrateContext;
+use mir::MirContext;
use libc::c_uint;
use std::ptr;
/// Sets the current debug location at the beginning of the span.
///
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...).
-pub fn set_source_location(fcx: &FunctionContext, builder: &Builder, scope: DIScope, span: Span) {
- let function_debug_context = match fcx.debug_context {
+pub fn set_source_location(mir: &MirContext, builder: &Builder, scope: DIScope, span: Span) {
+ let function_debug_context = match mir.debug_context {
FunctionDebugContext::DebugInfoDisabled => return,
FunctionDebugContext::FunctionWithoutDebugInfo => {
- set_debug_location(fcx.ccx, builder, UnknownLocation);
+ set_debug_location(mir.ccx(), builder, UnknownLocation);
return;
}
FunctionDebugContext::RegularContext(ref data) => data
};
let dbg_loc = if function_debug_context.source_locations_enabled.get() {
- debug!("set_source_location: {}", fcx.ccx.sess().codemap().span_to_string(span));
- let loc = span_start(fcx.ccx, span);
+ debug!("set_source_location: {}", mir.ccx().sess().codemap().span_to_string(span));
+ let loc = span_start(mir.ccx(), span);
InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
} else {
UnknownLocation
};
- set_debug_location(fcx.ccx, builder, dbg_loc);
+ set_debug_location(mir.ccx(), builder, dbg_loc);
}
/// Enables emitting source locations for the given functions.
/// they are disabled when beginning to translate 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 translated.
-pub fn start_emitting_source_locations(fcx: &FunctionContext) {
- match fcx.debug_context {
+pub fn start_emitting_source_locations(mir: &MirContext) {
+ match mir.debug_context {
FunctionDebugContext::RegularContext(ref data) => {
data.source_locations_enabled.set(true)
},
use common::{self, BlockAndBuilder, Funclet};
use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
use consts;
+use debuginfo;
use Disr;
use machine::{llalign_of_min, llbitsize_of_real};
use meth;
let span = terminator.source_info.span;
let (scope, debug_span) = self.debug_loc(terminator.source_info);
- bcx.set_source_location(scope, debug_span);
+ debuginfo::set_source_location(self, &bcx, scope, debug_span);
match terminator.kind {
mir::TerminatorKind::Resume => {
if let Some(cleanup_pad) = cleanup_pad {
// After this point, bcx is the block for the call to panic.
bcx = panic_block;
- bcx.set_source_location(scope, debug_span);
+ debuginfo::set_source_location(self, &bcx, scope, debug_span);
// Get the location information.
let loc = bcx.sess().codemap().lookup_char_pos(span.lo);
if let Some((_, target)) = *destination {
let ret_bcx = self.build_block(target);
ret_bcx.at_start(|ret_bcx| {
- bcx.set_source_location(scope, debug_span);
+ debuginfo::set_source_location(self, &ret_bcx, scope, debug_span);
let op = OperandRef {
val: Immediate(invokeret),
ty: sig.output(),
use base;
use common::{self, BlockAndBuilder, CrateContext, FunctionContext, C_null, Funclet};
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
+use monomorphize::Instance;
use machine;
use type_of;
use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
use syntax::symbol::keywords;
+use syntax::abi::Abi;
use std::iter;
/// Master context for translating MIR.
pub struct MirContext<'a, 'tcx:'a> {
- mir: &'a mir::Mir<'tcx>,
+ pub mir: &'a mir::Mir<'tcx>,
+
+ pub debug_context: debuginfo::FunctionDebugContext,
/// Function context
fcx: &'a common::FunctionContext<'a, 'tcx>,
impl<'a, 'tcx> MirContext<'a, 'tcx> {
pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) {
// Bail out if debug info emission is not enabled.
- match self.fcx.debug_context {
+ match self.debug_context {
FunctionDebugContext::DebugInfoDisabled |
FunctionDebugContext::FunctionWithoutDebugInfo => {
return (self.scopes[source_info.scope].scope_metadata, source_info.span);
scope_metadata
}
}
+
+ pub fn ccx(&self) -> &'a CrateContext<'a, 'tcx> {
+ self.fcx.ccx
+ }
}
enum LocalRef<'tcx> {
///////////////////////////////////////////////////////////////////////////
-pub fn trans_mir<'a, 'tcx: 'a>(fcx: &'a FunctionContext<'a, 'tcx>, mir: &'a Mir<'tcx>) {
+pub fn trans_mir<'a, 'tcx: 'a>(
+ fcx: &'a FunctionContext<'a, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ instance: Instance<'tcx>,
+ sig: &ty::FnSig<'tcx>,
+ abi: Abi,
+) {
+ let def_id = instance.def;
+ let local_id = fcx.ccx.tcx().map.as_local_node_id(def_id);
+ let no_debug = if let Some(id) = local_id {
+ fcx.ccx.tcx().map.attrs(id).iter().any(|item| item.check_name("no_debug"))
+ } else {
+ fcx.ccx.sess().cstore.item_attrs(def_id).iter().any(|item| item.check_name("no_debug"))
+ };
+
+ let debug_context = if !no_debug {
+ debuginfo::create_function_debug_context(fcx.ccx, instance, sig, abi, fcx.llfn, mir)
+ } else {
+ debuginfo::empty_function_debug_context(fcx.ccx)
+ };
let bcx = fcx.get_entry_block();
// Analyze the temps to determine which must be lvalues
}).collect();
// Compute debuginfo scopes from MIR scopes.
- let scopes = debuginfo::create_mir_scopes(fcx, mir);
+ let scopes = debuginfo::create_mir_scopes(fcx, mir, &debug_context);
let mut mircx = MirContext {
mir: mir,
landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
scopes: scopes,
locals: IndexVec::new(),
+ debug_context: debug_context,
};
// Allocate variable and temp allocas
mircx.locals = {
- let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
+ let args = arg_local_refs(&bcx, &mircx, &mircx.scopes, &lvalue_locals);
let mut allocate_local = |local| {
let decl = &mir.local_decls[local];
let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str());
if dbg {
let (scope, span) = mircx.debug_loc(source_info);
- declare_local(&bcx, name, ty, scope,
+ declare_local(&bcx, &mircx, name, ty, scope,
VariableAccess::DirectVariable { alloca: lvalue.llval },
VariableKind::LocalVariable, span);
}
// Up until here, IR instructions for this function have explicitly not been annotated with
// source code location, so we don't step into call setup code. From here on, source location
// emitting should be enabled.
- debuginfo::start_emitting_source_locations(fcx);
+ debuginfo::start_emitting_source_locations(&mircx);
let mut visited = BitVector::new(mir.basic_blocks().len());
/// argument's value. As arguments are lvalues, these are always
/// indirect.
fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
- mir: &mir::Mir<'tcx>,
+ mircx: &MirContext<'a, 'tcx>,
scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
lvalue_locals: &BitVector)
-> Vec<LocalRef<'tcx>> {
+ let mir = mircx.mir;
let fcx = bcx.fcx();
let tcx = bcx.tcx();
let mut idx = 0;
let variable_access = VariableAccess::DirectVariable {
alloca: lltemp
};
- declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()),
+ declare_local(bcx, mircx, arg_decl.name.unwrap_or(keywords::Invalid.name()),
arg_ty, scope, variable_access,
VariableKind::ArgumentVariable(arg_index + 1),
DUMMY_SP);
arg_scope.map(|scope| {
// Is this a regular argument?
if arg_index > 0 || mir.upvar_decls.is_empty() {
- declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
+ declare_local(bcx, mircx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty,
scope, VariableAccess::DirectVariable { alloca: llval },
VariableKind::ArgumentVariable(arg_index + 1),
DUMMY_SP);
alloca: env_ptr,
address_operations: &ops
};
- declare_local(bcx, decl.debug_name, ty, scope, variable_access,
+ declare_local(bcx, mircx, decl.debug_name, ty, scope, variable_access,
VariableKind::CapturedVariable,
DUMMY_SP);
}
use rustc::mir;
use base;
+use debuginfo;
use common::{self, BlockAndBuilder};
use super::MirContext;
debug!("trans_statement(statement={:?})", statement);
let (scope, span) = self.debug_loc(statement.source_info);
- bcx.set_source_location(scope, span);
+ debuginfo::set_source_location(self, &bcx, scope, span);
match statement.kind {
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
if let mir::Lvalue::Local(index) = *lvalue {