debuginfo: Support for variables captured in closures and closure type descriptions.

This commit is contained in:
Michael Woerister 2013-08-23 18:45:02 +02:00
parent 67555d9bd4
commit b81ea86530
11 changed files with 560 additions and 193 deletions

View file

@ -2084,6 +2084,25 @@ pub mod llvm {
ColumnNo: c_uint)
-> ValueRef;
#[fast_ffi]
pub fn LLVMDIBuilderCreateOpDeref(IntType: TypeRef) -> ValueRef;
#[fast_ffi]
pub fn LLVMDIBuilderCreateOpPlus(IntType: TypeRef) -> ValueRef;
#[fast_ffi]
pub fn LLVMDIBuilderCreateComplexVariable(Builder: DIBuilderRef,
Tag: c_uint,
Scope: ValueRef,
Name: *c_char,
File: ValueRef,
LineNo: c_uint,
Ty: ValueRef,
AddrOps: *ValueRef,
AddrOpsCount: c_uint,
ArgNo: c_uint)
-> ValueRef;
pub fn LLVMInitializeX86TargetInfo();
pub fn LLVMInitializeX86Target();
pub fn LLVMInitializeX86TargetMC();

View file

@ -143,7 +143,7 @@ use syntax::visit;
use syntax::visit::Visitor;
use syntax::codemap::Span;
#[deriving(Encodable, Decodable)]
#[deriving(Eq, Encodable, Decodable)]
pub enum CaptureMode {
CapCopy, // Copy the value into the closure.
CapMove, // Move the value into the closure.

View file

@ -131,20 +131,6 @@ pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
_InsnCtxt { _x: () }
}
fn fcx_has_nonzero_span(fcx: &FunctionContext) -> bool {
match fcx.span {
None => false,
Some(span) => *span.lo != 0 || *span.hi != 0
}
}
fn span_is_empty(opt_span: &Option<Span>) -> bool {
match *opt_span {
None => true,
Some(span) => *span.lo == 0 && *span.hi == 0
}
}
struct StatRecorder<'self> {
ccx: @mut CrateContext,
name: &'self str,
@ -1132,8 +1118,7 @@ pub fn trans_stmt(cx: @mut Block, s: &ast::Stmt) -> @mut Block {
match d.node {
ast::DeclLocal(ref local) => {
bcx = init_local(bcx, *local);
if cx.sess().opts.extra_debuginfo
&& fcx_has_nonzero_span(bcx.fcx) {
if cx.sess().opts.extra_debuginfo {
debuginfo::create_local_var_metadata(bcx, *local);
}
}
@ -1633,12 +1618,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
}
};
let uses_outptr = type_of::return_uses_outptr(ccx.tcx, substd_output_type);
let debug_context = if id != -1 && ccx.sess.opts.debuginfo && !span_is_empty(&sp) {
Some(debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl))
} else {
None
};
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
let fcx = @mut FunctionContext {
llfn: llfndecl,
@ -1784,7 +1764,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
add_clean(bcx, self_val, slf.t);
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
if fcx.ccx.sess.opts.extra_debuginfo {
debuginfo::create_self_argument_metadata(bcx, slf.t, self_val);
}
}
@ -1811,7 +1791,7 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
};
bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
if fcx.ccx.sess.opts.extra_debuginfo {
debuginfo::create_argument_metadata(bcx, &args[arg_n]);
}
}

View file

@ -17,6 +17,7 @@ use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::common::*;
use middle::trans::datum::{Datum, INIT};
use middle::trans::debuginfo;
use middle::trans::expr;
use middle::trans::glue;
use middle::trans::type_of::*;
@ -317,6 +318,11 @@ pub fn load_environment(fcx: @mut FunctionContext,
}
let def_id = ast_util::def_id_of_def(cap_var.def);
fcx.llupvars.insert(def_id.node, upvarptr);
if fcx.ccx.sess.opts.extra_debuginfo {
debuginfo::create_captured_var_metadata(bcx, def_id.node, upvarptr, cap_var.span);
}
i += 1u;
}
}

View file

@ -228,7 +228,7 @@ pub struct FunctionContext {
ccx: @mut CrateContext,
// Used and maintained by the debuginfo module.
debug_context: Option<~debuginfo::FunctionDebugContext>
debug_context: debuginfo::FunctionDebugContext,
}
impl FunctionContext {

View file

@ -72,7 +72,7 @@ use syntax::codemap::Span;
use syntax::{ast, codemap, ast_util, ast_map, opt_vec};
use syntax::parse::token::special_idents;
static DW_LANG_RUST: int = 0x9000;
static DW_LANG_RUST: c_uint = 0x9000;
static DW_TAG_auto_variable: c_uint = 0x100;
static DW_TAG_arg_variable: c_uint = 0x101;
@ -118,11 +118,63 @@ impl DebugContext {
}
}
pub struct FunctionDebugContext {
priv scope_map: HashMap<ast::NodeId, DIScope>,
priv fn_metadata: DISubprogram,
priv argument_counter: uint,
priv source_locations_enabled: bool,
pub enum FunctionDebugContext {
priv FunctionDebugContext(~FunctionDebugContextData),
priv DebugInfoDisabled,
priv FunctionWithoutDebugInfo,
}
impl FunctionDebugContext {
fn get_ref<'a>(&'a self, cx: &CrateContext, span: span) -> &'a FunctionDebugContextData {
match *self {
FunctionDebugContext(~ref data) => data,
DebugInfoDisabled => {
cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
although debug info is disabled!");
}
FunctionWithoutDebugInfo => {
cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
for function that should be ignored by debug info!");
}
}
}
fn get_mut_ref<'a>(&'a mut self,
cx: &CrateContext,
span: span)
-> &'a mut FunctionDebugContextData {
match *self {
FunctionDebugContext(~ref mut data) => data,
DebugInfoDisabled => {
cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
although debug info is disabled!");
}
FunctionWithoutDebugInfo => {
cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
for function that should be ignored by debug info!");
}
}
}
}
struct FunctionDebugContextData {
scope_map: HashMap<ast::NodeId, DIScope>,
fn_metadata: DISubprogram,
argument_counter: uint,
source_locations_enabled: bool,
}
enum VariableAccess {
// The value given is a pointer to data
DirectVariable,
// The value given has to be dereferenced once to get the pointer to data
IndirectVariable
}
enum VariableKind {
ArgumentVariable(uint /*index*/),
LocalVariable,
CapturedVariable,
}
/// Create any deferred debug metadata nodes
@ -138,7 +190,12 @@ pub fn finalize(cx: @mut CrateContext) {
/// Creates debug information for the given local variable.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) {
pub fn create_local_var_metadata(bcx: @mut Block,
local: &ast::Local) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let cx = bcx.ccx();
let def_map = cx.tcx.def_map;
@ -147,10 +204,66 @@ pub fn create_local_var_metadata(bcx: @mut Block, local: &ast::Local) {
let var_ident = ast_util::path_to_ident(path_ref);
let var_type = node_id_type(bcx, node_id);
declare_local(bcx, var_ident, node_id, var_type, span);
let llptr = match bcx.fcx.lllocals.find_copy(&node_id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(span, fmt!("No entry in lllocals table for %?", node_id));
}
};
let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
declare_local(bcx,
llptr,
var_ident,
var_type,
scope_metadata,
DirectVariable,
LocalVariable,
span);
}
}
/// Creates debug information for a local variable introduced in the head of a match-statement arm.
///
// /// Adds the created metadata nodes directly to the crate's IR.
pub fn create_captured_var_metadata(bcx: @mut Block,
node_id: ast::NodeId,
llptr: ValueRef,
span: span) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let cx = bcx.ccx();
let ast_item = cx.tcx.items.find_copy(&node_id);
let variable_ident = match ast_item {
None => {
cx.sess.span_bug(span, "debuginfo::create_captured_var_metadata() - NodeId not found");
}
Some(ast_map::node_local(ident)) => ident,
Some(ast_map::node_arg(@ast::pat { node: ast::pat_ident(_, ref path, _), _ })) => {
ast_util::path_to_ident(path)
}
_ => {
cx.sess.span_bug(span, fmt!("debuginfo::create_captured_var_metadata() - \
Captured var-id refers to unexpected ast_map variant: %?", ast_item));
}
};
let variable_type = node_id_type(bcx, node_id);
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, span).fn_metadata;
declare_local(bcx,
llptr,
variable_ident,
variable_type,
scope_metadata,
IndirectVariable,
CapturedVariable,
span);
}
/// Creates debug information for a local variable introduced in the head of a match-statement arm.
///
/// Adds the created metadata nodes directly to the crate's IR.
@ -158,62 +271,76 @@ pub fn create_match_binding_metadata(bcx: @mut Block,
variable_ident: ast::Ident,
node_id: ast::NodeId,
variable_type: ty::t,
span: Span) {
declare_local(bcx, variable_ident, node_id, variable_type, span);
span: span) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let llptr = match bcx.fcx.lllocals.find_copy(&node_id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(span, fmt!("No entry in lllocals table for %?", node_id));
}
};
let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
declare_local(bcx,
llptr,
variable_ident,
variable_type,
scope_metadata,
DirectVariable,
LocalVariable,
span);
}
/// Creates debug information for the self argument of a method.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_self_argument_metadata(bcx: @mut Block,
variable_type: ty::t,
type_of_self: ty::t,
llptr: ValueRef) {
assert_fcx_has_span(bcx.fcx);
let span = bcx.fcx.span.unwrap();
if fn_should_be_ignored(bcx.fcx) {
return;
}
let cx = bcx.ccx();
// Extract the span of the self argument from the method's AST
let fnitem = bcx.ccx().tcx.items.get_copy(&bcx.fcx.id);
let span = match fnitem {
ast_map::node_method(@ast::method { explicit_self: explicit_self, _ }, _, _) => {
explicit_self.span
}
ast_map::node_trait_method(
@ast::provided(
@ast::method {
explicit_self: explicit_self,
_
}),
_,
_) => {
explicit_self.span
}
_ => bcx.ccx().sess.bug(fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem))
};
let filename = span_start(cx, span).file.name;
let file_metadata = file_metadata(cx, filename);
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
let scope = bcx.fcx.debug_context.get_ref().fn_metadata;
let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata;
let argument_index = {
let counter = &mut bcx.fcx.debug_context.get_mut_ref().argument_counter;
let counter = &mut bcx.fcx.debug_context.get_mut_ref(bcx.ccx(), span).argument_counter;
let argument_index = *counter;
*counter += 1;
argument_index as c_uint
argument_index
};
let var_metadata = do cx.sess.str_of(special_idents::self_).to_c_str().with_ref |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_arg_variable,
scope,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
false,
0,
argument_index)
}
};
set_debug_location(cx, DebugLocation::new(scope, loc.line, *loc.col));
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx),
llptr,
var_metadata,
bcx.llbb);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
set_debug_location(cx, UnknownLocation);
declare_local(bcx,
llptr,
special_idents::self_,
type_of_self,
scope_metadata,
DirectVariable,
ArgumentVariable(argument_index),
span);
}
/// Creates debug information for the given function argument.
@ -221,54 +348,22 @@ pub fn create_self_argument_metadata(bcx: @mut Block,
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_argument_metadata(bcx: @mut Block,
arg: &ast::arg) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let fcx = bcx.fcx;
let cx = fcx.ccx;
let pattern = arg.pat;
let filename = span_start(cx, pattern.span).file.name;
if fcx.id == -1 ||
fcx.span.is_none() ||
"<intrinsic>" == filename {
return;
}
let def_map = cx.tcx.def_map;
let file_metadata = file_metadata(cx, filename);
let scope = bcx.fcx.debug_context.get_ref().fn_metadata;//create_function_metadata(fcx);
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata;
do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| {
let ty = node_id_type(bcx, node_id);
let type_metadata = type_metadata(cx, ty, codemap::dummy_sp());
let loc = span_start(cx, span);
let ident = ast_util::path_to_ident(path_ref);
let name: &str = cx.sess.str_of(ident);
debug!("create_argument_metadata: %s", name);
let argument_index = {
let counter = &mut fcx.debug_context.get_mut_ref().argument_counter;
let argument_index = *counter;
*counter += 1;
argument_index as c_uint
};
let arg_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_arg_variable,
scope,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
false,
0,
argument_index)
}
};
let llptr = match bcx.fcx.llargs.find_copy(&node_id) {
Some(v) => v,
None => {
@ -276,17 +371,24 @@ pub fn create_argument_metadata(bcx: @mut Block,
}
};
set_debug_location(cx, DebugLocation::new(scope, loc.line, *loc.col));
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx),
llptr,
arg_metadata,
bcx.llbb);
let argument_type = node_id_type(bcx, node_id);
let argument_ident = ast_util::path_to_ident(path_ref);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
set_debug_location(cx, UnknownLocation);
let argument_index = {
let counter = &mut fcx.debug_context.get_mut_ref(cx, span).argument_counter;
let argument_index = *counter;
*counter += 1;
argument_index
};
declare_local(bcx,
llptr,
argument_ident,
argument_type,
scope_metadata,
DirectVariable,
ArgumentVariable(argument_index),
span);
}
}
@ -296,16 +398,16 @@ pub fn create_argument_metadata(bcx: @mut Block,
/// reliably find the correct visibility scope for the code position.
pub fn set_source_location(fcx: &FunctionContext,
node_id: ast::NodeId,
span: Span) {
let cx: &mut CrateContext = fcx.ccx;
if !cx.sess.opts.debuginfo || (*span.lo == 0 && *span.hi == 0) {
span: span) {
if fn_should_be_ignored(fcx) {
return;
}
let cx = fcx.ccx;
debug!("set_source_location: %s", cx.sess.codemap.span_to_str(span));
if fcx.debug_context.get_ref().source_locations_enabled {
if fcx.debug_context.get_ref(cx, span).source_locations_enabled {
let loc = span_start(cx, span);
let scope = scope_metadata(fcx, node_id, span);
@ -316,16 +418,23 @@ pub fn set_source_location(fcx: &FunctionContext,
}
pub fn start_emitting_source_locations(fcx: &mut FunctionContext) {
for debug_context in fcx.debug_context.mut_iter() {
debug_context.source_locations_enabled = true;
match fcx.debug_context {
FunctionDebugContext(~ref mut data) => data.source_locations_enabled = true,
_ => { /* safe to ignore */}
}
}
pub fn create_function_debug_context(cx: &mut CrateContext,
fn_ast_id: ast::NodeId,
param_substs: Option<@param_substs>,
llfn: ValueRef) -> ~FunctionDebugContext {
assert!(fn_ast_id != -1);
llfn: ValueRef) -> FunctionDebugContext {
if !cx.sess.opts.debuginfo {
return DebugInfoDisabled;
}
if fn_ast_id == -1 {
return FunctionWithoutDebugInfo;
}
let empty_generics = ast::Generics { lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty };
@ -395,9 +504,18 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
_) => {
(ident, fn_decl, generics, None, span)
}
ast_map::node_variant(*) |
ast_map::node_struct_ctor(*) => {
return FunctionWithoutDebugInfo;
}
_ => cx.sess.bug(fmt!("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 FunctionWithoutDebugInfo;
}
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
@ -438,7 +556,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
};
// Initialize fn debug context (including scope map)
let mut fn_debug_context = ~FunctionDebugContext {
let mut fn_debug_context = ~FunctionDebugContextData {
scope_map: HashMap::new(),
fn_metadata: fn_metadata,
argument_counter: 1,
@ -448,7 +566,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map);
return fn_debug_context;
return FunctionDebugContext(fn_debug_context);
fn get_function_signature(cx: &mut CrateContext,
fn_ast_id: ast::NodeId,
@ -631,19 +749,28 @@ fn compile_unit_metadata(cx: @mut CrateContext) {
do "".with_c_str |flags| {
do "".with_c_str |split_name| {
unsafe {
llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder,
DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
llvm::LLVMDIBuilderCreateCompileUnit(
dcx.builder,
DW_LANG_RUST,
crate_name,
work_dir,
producer,
cx.sess.opts.optimize != session::No,
flags, 0, split_name);
flags,
0,
split_name);
}
}}}}};
}
fn declare_local(bcx: @mut Block,
variable_ident: ast::Ident,
node_id: ast::NodeId,
llptr: ValueRef,
variable_ident: ast::ident,
variable_type: ty::t,
span: Span) {
scope_metadata: DIScope,
variable_access: VariableAccess,
variable_kind: VariableKind,
span: span) {
let cx: &mut CrateContext = bcx.ccx();
let filename = span_start(cx, span).file.name;
@ -652,32 +779,48 @@ fn declare_local(bcx: @mut Block,
let name: &str = cx.sess.str_of(variable_ident);
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
let scope = scope_metadata(bcx.fcx, node_id, span);
let argument_index = match variable_kind {
ArgumentVariable(index) => index,
LocalVariable |
CapturedVariable => 0
} as c_uint;
let var_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_auto_variable,
scope,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
false,
0,
0)
match variable_access {
DirectVariable => unsafe {
llvm::LLVMDIBuilderCreateLocalVariable(
DIB(cx),
DW_TAG_auto_variable,
scope_metadata,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
cx.sess.opts.optimize != session::No,
0,
argument_index)
},
IndirectVariable => unsafe {
let address_op = llvm::LLVMDIBuilderCreateOpDeref(Type::i64().to_ref());
let address_op_count = 1;
llvm::LLVMDIBuilderCreateComplexVariable(
DIB(cx),
DW_TAG_auto_variable,
scope_metadata,
name,
file_metadata,
loc.line as c_uint,
type_metadata,
ptr::to_unsafe_ptr(&address_op),
address_op_count,
argument_index)
}
}
};
let llptr = match bcx.fcx.lllocals.find_copy(&node_id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(span, fmt!("No entry in lllocals table for %?", node_id));
}
};
set_debug_location(cx, DebugLocation::new(scope, loc.line, *loc.col));
set_debug_location(cx, DebugLocation::new(scope_metadata, loc.line, *loc.col));
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx),
@ -687,6 +830,14 @@ fn declare_local(bcx: @mut Block,
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
match variable_kind {
ArgumentVariable(_) | CapturedVariable => {
assert!(!bcx.fcx.debug_context.get_ref(cx, span).source_locations_enabled);
set_debug_location(cx, UnknownLocation);
}
_ => { /* fallthrough */ }
}
}
fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
@ -720,13 +871,9 @@ fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
/// Finds the scope metadata node for the given AST node.
fn scope_metadata(fcx: &FunctionContext,
node_id: ast::NodeId,
span: Span) -> DIScope {
if fcx.debug_context.is_none() {
fcx.ccx.sess.span_bug(span, "debuginfo: FunctionDebugContext should be initialized \
but is not!");
}
let scope_map = &fcx.debug_context.get_ref().scope_map;
span: span)
-> DIScope {
let scope_map = &fcx.debug_context.get_ref(fcx.ccx, span).scope_map;
match scope_map.find_copy(&node_id) {
Some(scope_metadata) => scope_metadata,
@ -1260,30 +1407,31 @@ fn vec_slice_metadata(cx: &mut CrateContext,
}
}
fn bare_fn_metadata(cx: &mut CrateContext,
_fn_ty: ty::t,
inputs: ~[ty::t],
output: ty::t,
span: Span)
-> DICompositeType {
debug!("bare_fn_metadata: %?", ty::get(_fn_ty));
fn subroutine_type_metadata(cx: &mut CrateContext,
signature: &ty::FnSig,
span: span)
-> DICompositeType {
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name);
let nil_pointer_type_metadata = type_metadata(cx, ty::mk_nil_ptr(cx.tcx), span);
let output_metadata = type_metadata(cx, output, span);
let output_ptr_metadata = pointer_type_metadata(cx, output, output_metadata);
let mut signature_metadata: ~[DIType] = vec::with_capacity(signature.inputs.len() + 1);
let inputs_vals = do inputs.map |arg| { type_metadata(cx, *arg, span) };
let members = ~[output_ptr_metadata, nil_pointer_type_metadata] + inputs_vals;
// return type
signature_metadata.push(match ty::get(signature.output).sty {
ty::ty_nil => ptr::null(),
_ => type_metadata(cx, signature.output, span)
});
// regular arguments
for &argument_type in signature.inputs.iter() {
signature_metadata.push(type_metadata(cx, argument_type, span));
}
return unsafe {
llvm::LLVMDIBuilderCreateSubroutineType(
DIB(cx),
file_metadata,
create_DIArray(DIB(cx), members))
create_DIArray(DIB(cx), signature_metadata))
};
}
@ -1407,13 +1555,10 @@ fn type_metadata(cx: &mut CrateContext,
pointer_type_metadata(cx, t, pointee)
},
ty::ty_bare_fn(ref barefnty) => {
let inputs = barefnty.sig.inputs.map(|a| *a);
let output = barefnty.sig.output;
bare_fn_metadata(cx, t, inputs, output, span)
subroutine_type_metadata(cx, &barefnty.sig, span)
},
ty::ty_closure(ref _closurety) => {
cx.sess.span_note(span, "debuginfo for closure NYI");
unimplemented_type_metadata(cx, t)
ty::ty_closure(ref closurety) => {
subroutine_type_metadata(cx, &closurety.sig, span)
},
ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
cx.sess.span_note(span, "debuginfo for trait NYI");
@ -1458,7 +1603,6 @@ fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) {
return;
}
let metadata_node;
match debug_location {
@ -1524,6 +1668,13 @@ fn assert_fcx_has_span(fcx: &FunctionContext) {
}
}
fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
match fcx.debug_context {
FunctionDebugContext(_) => false,
_ => true
}
}
// This procedure builds the *scope map* for a given function, which maps any given ast::NodeId in
// the function's AST to the correct DIScope metadata instance.
//

View file

@ -73,7 +73,7 @@ pub enum ast_node {
node_variant(variant, @item, @path),
node_expr(@Expr),
node_stmt(@Stmt),
node_arg,
node_arg(@pat),
node_local(Ident),
node_block(Block),
node_struct_ctor(@struct_def, @item, @path),
@ -171,7 +171,7 @@ impl Ctx {
sp: codemap::Span,
id: NodeId) {
for a in decl.inputs.iter() {
self.map.insert(a.id, node_arg);
self.map.insert(a.id, node_arg(a.pat));
}
visit::walk_fn(self, fk, decl, body, sp, id, ());
}
@ -487,8 +487,8 @@ pub fn node_id_to_str(map: map, id: NodeId, itr: @ident_interner) -> ~str {
fmt!("stmt %s (id=%?)",
pprust::stmt_to_str(stmt, itr), id)
}
Some(&node_arg) => {
fmt!("arg (id=%?)", id)
Some(&node_arg(pat)) => {
fmt!("arg %s (id=%?)", pprust::pat_to_str(pat, itr), id)
}
Some(&node_local(ident)) => {
fmt!("local (id=%?, name=%s)", id, itr.get(ident.name))

View file

@ -724,3 +724,39 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter(
LineNo,
ColumnNo));
}
extern "C" LLVMValueRef LLVMDIBuilderCreateOpDeref(LLVMTypeRef IntTy)
{
return LLVMConstInt(IntTy, DIBuilder::OpDeref, true);
}
extern "C" LLVMValueRef LLVMDIBuilderCreateOpPlus(LLVMTypeRef IntTy)
{
return LLVMConstInt(IntTy, DIBuilder::OpPlus, true);
}
extern "C" LLVMValueRef LLVMDIBuilderCreateComplexVariable(
DIBuilderRef Builder,
unsigned Tag,
LLVMValueRef Scope,
const char *Name,
LLVMValueRef File,
unsigned LineNo,
LLVMValueRef Ty,
LLVMValueRef* AddrOps,
unsigned AddrOpsCount,
unsigned ArgNo)
{
llvm::ArrayRef<llvm::Value*> addr_ops((llvm::Value**)AddrOps, AddrOpsCount);
return wrap(Builder->createComplexVariable(
Tag,
unwrapDI<DIDescriptor>(Scope),
Name,
unwrapDI<DIFile>(File),
LineNo,
unwrapDI<DIType>(Ty),
addr_ops,
ArgNo
));
}

View file

@ -0,0 +1,58 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print constant
// check:$1 = 1
// debugger:print a_struct
// check:$2 = {a = -2, b = 3.5, c = 4}
// debugger:print *owned
// check:$3 = 5
// debugger:print managed->val
// check:$4 = 6
#[allow(unused_variable)];
struct Struct {
a: int,
b: float,
c: uint
}
fn main() {
let constant = 1;
let a_struct = Struct {
a: -2,
b: 3.5,
c: 4
};
let owned = ~5;
let managed = @6;
let closure: @fn() = || {
zzz();
do_something(&constant, &a_struct.a, owned, managed);
};
closure();
}
fn do_something(_: &int, _:&int, _:&int, _:&int) {
}
fn zzz() {()}

View file

@ -0,0 +1,56 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print constant
// check:$1 = 1
// debugger:print a_struct
// check:$2 = {a = -2, b = 3.5, c = 4}
// debugger:print *owned
// check:$3 = 5
#[allow(unused_variable)];
struct Struct {
a: int,
b: float,
c: uint
}
fn main() {
let constant = 1;
let a_struct = Struct {
a: -2,
b: 3.5,
c: 4
};
let owned = ~5;
let closure: ~fn() = || {
zzz();
do_something(&constant, &a_struct.a, owned);
};
closure();
}
fn do_something(_: &int, _:&int, _:&int) {
}
fn zzz() {()}

View file

@ -0,0 +1,61 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print variable
// check:$1 = 1
// debugger:print constant
// check:$2 = 2
// debugger:print a_struct
// check:$3 = {a = -3, b = 4.5, c = 5}
// debugger:print *struct_ref
// check:$4 = {a = -3, b = 4.5, c = 5}
// debugger:print *owned
// check:$5 = 6
// debugger:print managed->val
// check:$6 = 7
#[allow(unused_variable)];
struct Struct {
a: int,
b: float,
c: uint
}
fn main() {
let mut variable = 1;
let constant = 2;
let a_struct = Struct {
a: -3,
b: 4.5,
c: 5
};
let struct_ref = &a_struct;
let owned = ~6;
let managed = @7;
let closure = || {
zzz();
variable = constant + a_struct.a + struct_ref.a + *owned + *managed;
};
closure();
}
fn zzz() {()}