body: &ast::Block,
llfndecl: ValueRef,
param_substs: ¶m_substs,
- id: ast::NodeId,
+ fn_ast_id: ast::NodeId,
_attributes: &[ast::Attribute],
arg_types: Vec<ty::t>,
output_type: ty::t,
let arena = TypedArena::new();
let fcx = new_fn_ctxt(ccx,
llfndecl,
- id,
+ fn_ast_id,
has_env,
output_type,
param_substs,
let mut bcx = init_function(&fcx, false, output_type);
// cleanup scope for the incoming arguments
- let arg_scope = fcx.push_custom_cleanup_scope();
+ let fn_cleanup_debug_loc =
+ debuginfo::get_cleanup_debug_loc_for_ast_node(fn_ast_id, body.span, true);
+ let arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc);
let block_ty = node_id_type(bcx, body.id);
ctor_ty: ty::t,
disr: ty::Disr,
args: callee::CallArgs,
- dest: expr::Dest) -> Result<'blk, 'tcx> {
+ dest: expr::Dest,
+ call_info: Option<NodeInfo>)
+ -> Result<'blk, 'tcx> {
let ccx = bcx.fcx.ccx;
let tcx = ccx.tcx();
match args {
callee::ArgExprs(exprs) => {
let fields = exprs.iter().map(|x| &**x).enumerate().collect::<Vec<_>>();
- bcx = expr::trans_adt(bcx, result_ty, disr, fields.as_slice(),
- None, expr::SaveIn(llresult));
+ bcx = expr::trans_adt(bcx,
+ result_ty,
+ disr,
+ fields.as_slice(),
+ None,
+ expr::SaveIn(llresult),
+ call_info);
}
_ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor")
}
// drop the temporary we made
let bcx = match dest {
expr::SaveIn(_) => bcx,
- expr::Ignore => glue::drop_ty(bcx, llresult, result_ty)
+ expr::Ignore => {
+ glue::drop_ty(bcx, llresult, result_ty, call_info)
+ }
};
Result::new(bcx, llresult)
fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
let ctor_ty = callee_ty.subst(bcx.tcx(), &substs);
- return base::trans_named_tuple_constructor(bcx, ctor_ty, disr,
- args, dest.unwrap());
+ return base::trans_named_tuple_constructor(bcx,
+ ctor_ty,
+ disr,
+ args,
+ dest.unwrap(),
+ call_info);
}
};
match (dest, opt_llretslot) {
(Some(expr::Ignore), Some(llretslot)) => {
// drop the value if it is not being saved.
- bcx = glue::drop_ty(bcx, llretslot, ret_ty);
+ bcx = glue::drop_ty(bcx, llretslot, ret_ty, call_info);
call_lifetime_end(bcx, llretslot);
}
_ => {}
use middle::trans::build;
use middle::trans::callee;
use middle::trans::common;
-use middle::trans::common::{Block, FunctionContext, ExprId};
+use middle::trans::common::{Block, FunctionContext, ExprId, NodeInfo};
+use middle::trans::debuginfo;
use middle::trans::glue;
use middle::trans::type_::Type;
use middle::ty;
// Cleanups to run upon scope exit.
cleanups: Vec<CleanupObj>,
+ // The debug location any drop calls generated for this scope will be
+ // associated with.
+ debug_loc: Option<NodeInfo>,
+
cached_early_exits: Vec<CachedEarlyExit>,
cached_landing_pad: Option<BasicBlockRef>,
}
pub trait Cleanup {
fn must_unwind(&self) -> bool;
fn clean_on_unwind(&self) -> bool;
- fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx>;
+ fn trans<'blk, 'tcx>(&self,
+ bcx: Block<'blk, 'tcx>,
+ debug_loc: Option<NodeInfo>)
+ -> Block<'blk, 'tcx>;
}
pub type CleanupObj = Box<Cleanup+'static>;
}
impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
- fn push_ast_cleanup_scope(&self, id: ast::NodeId) {
+ fn push_ast_cleanup_scope(&self, debug_loc: NodeInfo) {
/*!
* Invoked when we start to trans the code contained
* within a new cleanup scope.
*/
debug!("push_ast_cleanup_scope({})",
- self.ccx.tcx().map.node_to_string(id));
+ self.ccx.tcx().map.node_to_string(debug_loc.id));
// FIXME(#2202) -- currently closure bodies have a parent
// region, which messes up the assertion below, since there
// this new AST scope had better be its immediate child.
let top_scope = self.top_ast_scope();
if top_scope.is_some() {
- assert_eq!(self.ccx.tcx().region_maps.opt_encl_scope(id), top_scope);
+ assert_eq!(self.ccx
+ .tcx()
+ .region_maps
+ .opt_encl_scope(debug_loc.id),
+ top_scope);
}
- self.push_scope(CleanupScope::new(AstScopeKind(id)));
+ self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id),
+ Some(debug_loc)));
}
fn push_loop_cleanup_scope(&self,
self.ccx.tcx().map.node_to_string(id));
assert_eq!(Some(id), self.top_ast_scope());
- self.push_scope(CleanupScope::new(LoopScopeKind(id, exits)));
+ // Just copy the debuginfo source location from the enclosing scope
+ let debug_loc = self.scopes
+ .borrow()
+ .last()
+ .unwrap()
+ .debug_loc;
+
+ self.push_scope(CleanupScope::new(LoopScopeKind(id, exits), debug_loc));
}
fn push_custom_cleanup_scope(&self) -> CustomScopeIndex {
let index = self.scopes_len();
debug!("push_custom_cleanup_scope(): {}", index);
- self.push_scope(CleanupScope::new(CustomScopeKind));
+
+ // Just copy the debuginfo source location from the enclosing scope
+ let debug_loc = self.scopes
+ .borrow()
+ .last()
+ .map(|opt_scope| opt_scope.debug_loc)
+ .unwrap_or(None);
+
+ self.push_scope(CleanupScope::new(CustomScopeKind, debug_loc));
+ CustomScopeIndex { index: index }
+ }
+
+ fn push_custom_cleanup_scope_with_debug_loc(&self,
+ debug_loc: NodeInfo)
+ -> CustomScopeIndex {
+ let index = self.scopes_len();
+ debug!("push_custom_cleanup_scope(): {}", index);
+
+ self.push_scope(CleanupScope::new(CustomScopeKind, Some(debug_loc)));
CustomScopeIndex { index: index }
}
let scope = self.pop_scope();
self.trans_scope_cleanups(bcx, &scope)
-
}
fn pop_loop_cleanup_scope(&self,
}
fn pop_and_trans_custom_cleanup_scope(&self,
- bcx: Block<'blk, 'tcx>,
- custom_scope: CustomScopeIndex)
- -> Block<'blk, 'tcx> {
+ bcx: Block<'blk, 'tcx>,
+ custom_scope: CustomScopeIndex)
+ -> Block<'blk, 'tcx> {
/*!
* Removes the top cleanup scope from the stack, which must be
* a temporary scope, and generates the code to do its
let mut bcx = bcx;
if !bcx.unreachable.get() {
for cleanup in scope.cleanups.iter().rev() {
- bcx = cleanup.trans(bcx);
+ bcx = cleanup.trans(bcx, scope.debug_loc);
}
}
bcx
let mut bcx_out = bcx_in;
for cleanup in scope.cleanups.iter().rev() {
if cleanup_is_suitable_for(&**cleanup, label) {
- bcx_out = cleanup.trans(bcx_out);
+ bcx_out = cleanup.trans(bcx_out,
+ scope.debug_loc);
}
}
build::Br(bcx_out, prev_llbb);
}
impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> {
- fn new(kind: CleanupScopeKind<'blk, 'tcx>) -> CleanupScope<'blk, 'tcx> {
+ fn new(kind: CleanupScopeKind<'blk, 'tcx>,
+ debug_loc: Option<NodeInfo>)
+ -> CleanupScope<'blk, 'tcx> {
CleanupScope {
kind: kind,
+ debug_loc: debug_loc,
cleanups: vec!(),
cached_early_exits: vec!(),
cached_landing_pad: None,
self.must_unwind
}
- fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+ fn trans<'blk, 'tcx>(&self,
+ bcx: Block<'blk, 'tcx>,
+ debug_loc: Option<NodeInfo>)
+ -> Block<'blk, 'tcx> {
let bcx = if self.is_immediate {
- glue::drop_ty_immediate(bcx, self.val, self.ty)
+ glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc)
} else {
- glue::drop_ty(bcx, self.val, self.ty)
+ glue::drop_ty(bcx, self.val, self.ty, debug_loc)
};
if self.zero {
base::zero_mem(bcx, self.val, self.ty);
true
}
- fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+ fn trans<'blk, 'tcx>(&self,
+ bcx: Block<'blk, 'tcx>,
+ debug_loc: Option<NodeInfo>)
+ -> Block<'blk, 'tcx> {
+ apply_debug_loc(bcx.fcx, debug_loc);
+
match self.heap {
HeapManaged => {
glue::trans_free(bcx, self.ptr)
true
}
- fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+ fn trans<'blk, 'tcx>(&self,
+ bcx: Block<'blk, 'tcx>,
+ debug_loc: Option<NodeInfo>)
+ -> Block<'blk, 'tcx> {
+ apply_debug_loc(bcx.fcx, debug_loc);
+
match self.heap {
HeapManaged => {
glue::trans_free(bcx, self.ptr)
true
}
- fn trans<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) -> Block<'blk, 'tcx> {
+ fn trans<'blk, 'tcx>(&self,
+ bcx: Block<'blk, 'tcx>,
+ debug_loc: Option<NodeInfo>)
+ -> Block<'blk, 'tcx> {
+ apply_debug_loc(bcx.fcx, debug_loc);
base::call_lifetime_end(bcx, self.ptr);
bcx
}
!label.is_unwind() || c.clean_on_unwind()
}
+fn apply_debug_loc(fcx: &FunctionContext, debug_loc: Option<NodeInfo>) {
+ match debug_loc {
+ Some(ref src_loc) => {
+ debuginfo::set_source_location(fcx, src_loc.id, src_loc.span);
+ }
+ None => {
+ debuginfo::clear_source_location(fcx);
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// These traits just exist to put the methods into this file.
pub trait CleanupMethods<'blk, 'tcx> {
- fn push_ast_cleanup_scope(&self, id: ast::NodeId);
+ fn push_ast_cleanup_scope(&self, id: NodeInfo);
fn push_loop_cleanup_scope(&self,
- id: ast::NodeId,
- exits: [Block<'blk, 'tcx>, ..EXIT_MAX]);
+ id: ast::NodeId,
+ exits: [Block<'blk, 'tcx>, ..EXIT_MAX]);
fn push_custom_cleanup_scope(&self) -> CustomScopeIndex;
+ fn push_custom_cleanup_scope_with_debug_loc(&self,
+ debug_loc: NodeInfo)
+ -> CustomScopeIndex;
fn pop_and_trans_ast_cleanup_scope(&self,
bcx: Block<'blk, 'tcx>,
cleanup_scope: ast::NodeId)
use middle::trans::common::*;
use middle::trans::consts;
use middle::trans::datum;
+use middle::trans::debuginfo;
use middle::trans::expr;
use middle::trans::meth;
use middle::trans::type_::Type;
let mut bcx = cx;
let id = ast_util::stmt_id(s);
- fcx.push_ast_cleanup_scope(id);
+ let cleanup_debug_loc =
+ debuginfo::get_cleanup_debug_loc_for_ast_node(id, s.span, false);
+ fcx.push_ast_cleanup_scope(cleanup_debug_loc);
match s.node {
ast::StmtExpr(ref e, _) | ast::StmtSemi(ref e, _) => {
ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
}
- bcx = fcx.pop_and_trans_ast_cleanup_scope(
- bcx, ast_util::stmt_id(s));
+ bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, ast_util::stmt_id(s));
return bcx;
}
let fcx = bcx.fcx;
let mut bcx = bcx;
- fcx.push_ast_cleanup_scope(b.id);
+ let cleanup_debug_loc =
+ debuginfo::get_cleanup_debug_loc_for_ast_node(b.id, b.span, true);
+ fcx.push_ast_cleanup_scope(cleanup_debug_loc);
for s in b.stmts.iter() {
bcx = trans_stmt(bcx, &**s);
})
}
+pub fn get_cleanup_debug_loc_for_ast_node(node_id: ast::NodeId,
+ node_span: Span,
+ is_block: bool)
+ -> NodeInfo {
+ // A debug location needs two things:
+ // (1) A span (of which only the beginning will actually be used)
+ // (2) An AST node-id which will be used to look up the lexical scope
+ // for the location in the functions scope-map
+ //
+ // This function will calculate the debug location for compiler-generated
+ // cleanup calls that are executed when control-flow leaves the
+ // scope identified by `node_id`.
+ //
+ // For everything but block-like things we can simply take id and span of
+ // the given expression, meaning that from a debugger's view cleanup code is
+ // executed at the same source location as the statement/expr itself.
+ //
+ // Blocks are a special case. Here we want the cleanup to be linked to the
+ // closing curly brace of the block. The *scope* the cleanup is executed in
+ // is up to debate: It could either still be *within* the block being
+ // cleaned up, meaning that locals from the block are still visible in the
+ // debugger.
+ // Or it could be in the scope that the block is contained in, so any locals
+ // from within the block are already considered out-of-scope and thus not
+ // accessible in the debugger anymore.
+ //
+ // The current implementation opts for the second option: cleanup of a block
+ // already happens in the parent scope of the block. The main reason for
+ // this decision is that scoping becomes controlflow dependent when variable
+ // shadowing is involved and it's impossible to decide statically which
+ // scope is actually left when the cleanup code is executed.
+ // In practice it shouldn't make much of a difference.
+
+ let cleanup_span = if is_block {
+ Span {
+ lo: node_span.hi - codemap::BytePos(1), // closing brace should always be 1 byte...
+ hi: node_span.hi,
+ expn_id: node_span.expn_id
+ }
+ } else {
+ node_span
+ };
+
+ NodeInfo {
+ id: node_id,
+ span: cleanup_span
+ }
+}
+
/// Sets the current debug location at the beginning of the span.
///
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). The node_id
// Do this here already, in case we do an early exit from this function.
set_debug_location(cx, UnknownLocation);
- if fn_ast_id == -1 {
+ 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 { repr: FunctionWithoutDebugInfo };
}
fn_decl.inputs.as_slice(),
&*top_level_block,
fn_metadata,
+ fn_ast_id,
&mut *fn_debug_context.scope_map.borrow_mut());
return FunctionDebugContext { repr: DebugInfo(fn_debug_context) };
fn_ast_id: ast::NodeId,
fn_decl: &ast::FnDecl,
param_substs: ¶m_substs,
- error_span: Span) -> DIArray {
+ error_reporting_span: Span) -> DIArray {
if cx.sess().opts.debuginfo == LimitedDebugInfo {
return create_DIArray(DIB(cx), []);
}
signature.push(ptr::null_mut());
}
_ => {
- assert_type_for_node_id(cx, fn_ast_id, error_span);
+ assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id);
let return_type = return_type.substp(cx.tcx(), param_substs);
/// Finds the scope metadata node for the given AST node.
fn scope_metadata(fcx: &FunctionContext,
node_id: ast::NodeId,
- span: Span)
+ error_reporting_span: Span)
-> DIScope {
- let scope_map = &fcx.debug_context.get_ref(fcx.ccx, span).scope_map;
+ let scope_map = &fcx.debug_context
+ .get_ref(fcx.ccx, error_reporting_span)
+ .scope_map;
match scope_map.borrow().find_copy(&node_id) {
Some(scope_metadata) => scope_metadata,
None => {
let node = fcx.ccx.tcx().map.get(node_id);
- fcx.ccx.sess().span_bug(span,
+ fcx.ccx.sess().span_bug(error_reporting_span,
format!("debuginfo: Could not find scope info for node {:?}",
node).as_slice());
}
}
}
-fn assert_type_for_node_id(cx: &CrateContext, node_id: ast::NodeId, error_span: Span) {
+fn assert_type_for_node_id(cx: &CrateContext,
+ node_id: ast::NodeId,
+ error_reporting_span: Span) {
if !cx.tcx().node_types.borrow().contains_key(&(node_id as uint)) {
- cx.sess().span_bug(error_span, "debuginfo: Could not find type for node id!");
+ cx.sess().span_bug(error_reporting_span,
+ "debuginfo: Could not find type for node id!");
}
}
args: &[ast::Arg],
fn_entry_block: &ast::Block,
fn_metadata: DISubprogram,
+ fn_ast_id: ast::NodeId,
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
let def_map = &cx.tcx().def_map;
let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata,
ident: None });
+ scope_map.insert(fn_ast_id, fn_metadata);
// Push argument identifiers onto the stack so arguments integrate nicely
// with variable shadowing.
for arg in args.iter() {
- pat_util::pat_bindings(def_map, &*arg.pat, |_, _, _, path1| {
+ pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| {
scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
ident: Some(path1.node) });
+ scope_map.insert(node_id, fn_metadata);
})
}
}
debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
- debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
- bcx.fcx.push_ast_cleanup_scope(expr.id);
+ let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(expr.id,
+ expr.span,
+ false);
+ bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
+ debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
let kind = ty::expr_kind(bcx.tcx(), expr);
bcx = match kind {
ty::LvalueExpr | ty::RvalueDatumExpr => {
let mut bcx = bcx;
let fcx = bcx.fcx;
- fcx.push_ast_cleanup_scope(expr.id);
+ let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(expr.id,
+ expr.span,
+ false);
+ fcx.push_ast_cleanup_scope(cleanup_debug_loc);
let datum = unpack_datum!(bcx, trans_unadjusted(bcx, expr));
let datum = unpack_datum!(bcx, apply_adjustments(bcx, expr, datum));
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id);
match x.node {
ast::ExprRepeat(..) | ast::ExprVec(..) => {
// Special case for slices.
- fcx.push_ast_cleanup_scope(x.id);
+ let cleanup_debug_loc =
+ debuginfo::get_cleanup_debug_loc_for_ast_node(x.id, x.span, false);
+ fcx.push_ast_cleanup_scope(cleanup_debug_loc);
let datum = unpack_datum!(
bcx, tvec::trans_slice_vec(bcx, expr, &**x));
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
return bcx;
}
+ debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
+
match expr.node {
ast::ExprParen(ref e) => {
trans_into(bcx, &**e, Ignore)
//
// We could avoid this intermediary with some analysis
// to determine whether `dst` may possibly own `src`.
+ debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
let src_datum = unpack_datum!(
bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
- bcx = glue::drop_ty(bcx, dst_datum.val, dst_datum.ty);
+ bcx = glue::drop_ty(bcx,
+ dst_datum.val,
+ dst_datum.ty,
+ Some(NodeInfo { id: expr.id, span: expr.span }));
src_datum.store_to(bcx, dst_datum.val)
} else {
trans_into(bcx, &**src, SaveIn(dst_datum.to_llref()))
let mut bcx = bcx;
let tcx = bcx.tcx();
+ debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
+
match expr.node {
ast::ExprParen(ref e) => {
trans_into(bcx, &**e, dest)
ast::ExprTup(ref args) => {
let numbered_fields: Vec<(uint, &ast::Expr)> =
args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
- trans_adt(bcx, expr_ty(bcx, expr), 0, numbered_fields.as_slice(), None, dest)
+ trans_adt(bcx,
+ expr_ty(bcx, expr),
+ 0,
+ numbered_fields.as_slice(),
+ None,
+ dest,
+ Some(NodeInfo { id: expr.id, span: expr.span }))
}
ast::ExprLit(ref lit) => {
match lit.node {
fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
fields: &[ast::Field],
- base: Option<&ast::Expr>,
+ base: Option<&ast::Expr>,
expr_span: codemap::Span,
- id: ast::NodeId,
+ expr_id: ast::NodeId,
dest: Dest) -> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_rec");
- let ty = node_id_type(bcx, id);
+ let ty = node_id_type(bcx, expr_id);
let tcx = bcx.tcx();
- with_field_tys(tcx, ty, Some(id), |discr, field_tys| {
+ with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| {
let mut need_base = Vec::from_elem(field_tys.len(), true);
let numbered_fields = fields.iter().map(|field| {
}
};
- trans_adt(bcx, ty, discr, numbered_fields.as_slice(), optbase, dest)
+ trans_adt(bcx,
+ ty,
+ discr,
+ numbered_fields.as_slice(),
+ optbase,
+ dest,
+ Some(NodeInfo { id: expr_id, span: expr_span }))
})
}
discr: ty::Disr,
fields: &[(uint, &ast::Expr)],
optbase: Option<StructBaseInfo>,
- dest: Dest) -> Block<'blk, 'tcx> {
+ dest: Dest,
+ source_location: Option<NodeInfo>)
+ -> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_adt");
let fcx = bcx.fcx;
let repr = adt::represent_type(bcx.ccx(), ty);
+ match source_location {
+ Some(src_loc) => debuginfo::set_source_location(bcx.fcx,
+ src_loc.id,
+ src_loc.span),
+ None => {}
+ };
+
// If we don't care about the result, just make a
// temporary stack slot
let addr = match dest {
}
}
+ match source_location {
+ Some(src_loc) => debuginfo::set_source_location(bcx.fcx,
+ src_loc.id,
+ src_loc.span),
+ None => {}
+ };
+
// Now, we just overwrite the fields we've explicitly specified
for &(i, ref e) in fields.iter() {
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
match dest {
SaveIn(_) => bcx,
Ignore => {
- bcx = glue::drop_ty(bcx, addr, ty);
+ bcx = glue::drop_ty(bcx, addr, ty, source_location);
base::call_lifetime_end(bcx, addr);
bcx
}
use middle::trans::cleanup::CleanupMethods;
use middle::trans::common::*;
use middle::trans::datum;
+use middle::trans::debuginfo;
use middle::trans::expr;
use middle::trans::machine::*;
use middle::trans::reflect;
}
}
-pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
+pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ v: ValueRef,
+ t: ty::t,
+ source_location: Option<NodeInfo>)
-> Block<'blk, 'tcx> {
// NB: v is an *alias* of type t here, not a direct value.
debug!("drop_ty(t={})", t.repr(bcx.tcx()));
} else {
v
};
+
+ match source_location {
+ Some(sl) => debuginfo::set_source_location(bcx.fcx, sl.id, sl.span),
+ None => debuginfo::clear_source_location(bcx.fcx)
+ };
+
Call(bcx, glue, [ptr], None);
}
bcx
}
-pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
+pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ v: ValueRef,
+ t: ty::t,
+ source_location: Option<NodeInfo>)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("drop_ty_immediate");
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
Store(bcx, v, vp);
- drop_ty(bcx, vp, t)
+ drop_ty(bcx, vp, t, source_location)
}
pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef {
let llbox = Load(bcx, llval);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
- let bcx = drop_ty(bcx, v0, content_ty);
+ let bcx = drop_ty(bcx, v0, content_ty, None);
let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
let info = Load(bcx, info);
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
let llbox = Load(bcx, llval);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
- let bcx = drop_ty(bcx, llbox, content_ty);
+ let bcx = drop_ty(bcx, llbox, content_ty, None);
trans_exchange_free_ty(bcx, llbox, content_ty)
})
}
}
ty::NoDtor => {
// No dtor? Just the default case
- iter_structural_ty(bcx, v0, t, drop_ty)
+ iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
}
}
}
- ty::ty_unboxed_closure(..) => iter_structural_ty(bcx, v0, t, drop_ty),
+ ty::ty_unboxed_closure(..) => iter_structural_ty(bcx,
+ v0,
+ t,
+ |bb, vv, tt| drop_ty(bb, vv, tt, None)),
ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
let env = Load(bcx, box_cell_v);
assert!(ty::type_is_sized(bcx.tcx(), t));
if ty::type_needs_drop(bcx.tcx(), t) &&
ty::type_is_structural(t) {
- iter_structural_ty(bcx, v0, t, drop_ty)
+ iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
} else {
bcx
}
let v = Load(free_bcx, box_ptr_ptr);
let body = GEPi(free_bcx, v, [0u, abi::box_field_body]);
- let free_bcx = drop_ty(free_bcx, body, t);
+ let free_bcx = drop_ty(free_bcx, body, t, None);
let free_bcx = trans_free(free_bcx, v);
Br(free_bcx, next_bcx.llbb);
// If we made a temporary stack slot, let's clean it up
match dest {
expr::Ignore => {
- bcx = glue::drop_ty(bcx, llresult, ret_ty);
+ bcx = glue::drop_ty(bcx, llresult, ret_ty, Some(call_info));
}
expr::SaveIn(_) => {}
}
let dataptr = get_dataptr(bcx, vptr);
let bcx = if ty::type_needs_drop(tcx, unit_ty) {
let len = get_len(bcx, vptr);
- iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty)
+ iter_vec_raw(bcx, dataptr, unit_ty, len, |bb, vv, tt| glue::drop_ty(bb, vv, tt, None))
} else {
bcx
};
let i32_val: i32 = -32;
let i32_ref: &i32 = &i32_val;
- let uint_val: i64 = -64;
- let i64_ref: &i64 = &uint_val;
+ let i64_val: i64 = -64;
+ let i64_ref: &i64 = &i64_val;
let uint_val: uint = 1;
let uint_ref: &uint = &uint_val;