diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index b5404e38ec9..93fe258d167 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -23,7 +23,7 @@ fn target_env(lib_path: &str, prog: &str) -> ~[(~str,~str)] { assert!(prog.ends_with(".exe")); let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ".libaux"; - env = do vec::map(env) |pair| { + env = do env.map() |pair| { let (k,v) = copy *pair; if k == ~"PATH" { (~"PATH", v + ";" + lib_path + ";" + aux_path) } else { (k,v) } diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 289bb4f63f5..835dd55711b 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -224,13 +224,50 @@ pub type SectionIteratorRef = *SectionIterator_opaque; pub enum Pass_opaque {} pub type PassRef = *Pass_opaque; +pub mod debuginfo { + use super::{ValueRef}; + + pub enum DIBuilder_opaque {} + pub type DIBuilderRef = *DIBuilder_opaque; + + pub type DIDescriptor = ValueRef; + pub type DIScope = DIDescriptor; + pub type DILocation = DIDescriptor; + pub type DIFile = DIScope; + pub type DILexicalBlock = DIScope; + pub type DISubprogram = DIScope; + pub type DIType = DIDescriptor; + pub type DIBasicType = DIType; + pub type DIDerivedType = DIType; + pub type DICompositeType = DIDerivedType; + pub type DIVariable = DIDescriptor; + pub type DIArray = DIDescriptor; + pub type DISubrange = DIDescriptor; + + pub enum DIDescriptorFlags { + FlagPrivate = 1 << 0, + FlagProtected = 1 << 1, + FlagFwdDecl = 1 << 2, + FlagAppleBlock = 1 << 3, + FlagBlockByrefStruct = 1 << 4, + FlagVirtual = 1 << 5, + FlagArtificial = 1 << 6, + FlagExplicit = 1 << 7, + FlagPrototyped = 1 << 8, + FlagObjcClassComplete = 1 << 9, + FlagObjectPointer = 1 << 10, + FlagVector = 1 << 11, + FlagStaticMember = 1 << 12 + } +} + pub mod llvm { use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef, ExecutionEngineRef}; use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef}; use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef}; use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef}; - use super::{ValueRef,PassRef}; - + use super::{ValueRef, PassRef}; + use super::debuginfo::*; use core::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong}; #[link_args = "-Lrustllvm -lrustllvm"] @@ -929,6 +966,12 @@ pub mod llvm { #[fast_ffi] pub unsafe fn LLVMDeleteBasicBlock(BB: BasicBlockRef); + #[fast_ffi] + pub unsafe fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, MoveAfter: BasicBlockRef); + + #[fast_ffi] + pub unsafe fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, MoveBefore: BasicBlockRef); + /* Operations on instructions */ #[fast_ffi] pub unsafe fn LLVMGetInstructionParent(Inst: ValueRef) @@ -1885,6 +1928,164 @@ pub mod llvm { AlignStack: Bool, Dialect: c_uint) -> ValueRef; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderDispose(Builder: DIBuilderRef); + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderFinalize(Builder: DIBuilderRef); + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateCompileUnit( + Builder: DIBuilderRef, + Lang: c_uint, + File: *c_char, + Dir: *c_char, + Producer: *c_char, + isOptimized: bool, + Flags: *c_char, + RuntimeVer: c_uint, + SplitName: *c_char); + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateFile( + Builder: DIBuilderRef, + Filename: *c_char, + Directory: *c_char) -> DIFile; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateSubroutineType( + Builder: DIBuilderRef, + File: DIFile, + ParameterTypes: DIArray) -> DICompositeType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateFunction( + Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *c_char, + LinkageName: *c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + isDefinition: bool, + ScopeLine: c_uint, + Flags: c_uint, + isOptimized: bool, + Fn: ValueRef, + TParam: ValueRef, + Decl: ValueRef) -> DISubprogram; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateBasicType( + Builder: DIBuilderRef, + Name: *c_char, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Encoding: c_uint) -> DIBasicType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreatePointerType( + Builder: DIBuilderRef, + PointeeTy: DIType, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Name: *c_char) -> DIDerivedType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateStructType( + Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Flags: c_uint, + DerivedFrom: DIType, + Elements: DIArray, + RunTimeLang: c_uint, + VTableHolder: ValueRef) -> DICompositeType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateMemberType( + Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *c_char, + File: DIFile, + LineNo: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + OffsetInBits: c_ulonglong, + Flags: c_uint, + Ty: DIType) -> DIDerivedType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateLexicalBlock( + Builder: DIBuilderRef, + Scope: DIDescriptor, + File: DIFile, + Line: c_uint, + Col: c_uint) -> DILexicalBlock; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateLocalVariable( + Builder: DIBuilderRef, + Tag: c_uint, + Scope: DIDescriptor, + Name: *c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + AlwaysPreserve: bool, + Flags: c_uint, + ArgNo: c_uint) -> DIVariable; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateArrayType( + Builder: DIBuilderRef, + Size: c_ulonglong, + AlignInBits: c_ulonglong, + Ty: DIType, + Subscripts: DIArray) -> DIType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateVectorType( + Builder: DIBuilderRef, + Size: c_ulonglong, + AlignInBits: c_ulonglong, + Ty: DIType, + Subscripts: DIArray) -> DIType; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderGetOrCreateSubrange( + Builder: DIBuilderRef, + Lo: c_longlong, + Count: c_longlong) -> DISubrange; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderGetOrCreateArray( + Builder: DIBuilderRef, + Ptr: *DIDescriptor, + Count: c_uint) -> DIArray; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderInsertDeclareAtEnd( + Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + InsertAtEnd: BasicBlockRef) -> ValueRef; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderInsertDeclareBefore( + Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + InsertBefore: ValueRef) -> ValueRef; } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 53f2729c38e..55fc22a8fcc 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1908,6 +1908,12 @@ pub fn trans_closure(ccx: @mut CrateContext, finish(bcx); cleanup_and_Br(bcx, bcx_top, fcx.llreturn); + // Put return block after all other blocks. + // This somewhat improves single-stepping experience in debugger. + unsafe { + llvm::LLVMMoveBasicBlockAfter(fcx.llreturn, bcx.llbb); + } + // Insert the mandatory first few basic blocks before lltop. finish_fn(fcx, lltop); } @@ -3102,6 +3108,9 @@ pub fn trans_crate(sess: session::Session, fill_crate_map(ccx, ccx.crate_map); glue::emit_tydescs(ccx); write_abi_version(ccx); + if ccx.sess.opts.debuginfo { + debuginfo::finalize(ccx); + } // Translate the metadata. write_metadata(ccx, crate); diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 75d7aaa88a6..7aab1d0239e 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -148,7 +148,7 @@ impl CrateContext { lib::llvm::associate_type(tn, @"tydesc", tydesc_type); let crate_map = decl_crate_map(sess, link_meta, llmod); let dbg_cx = if sess.opts.debuginfo { - Some(debuginfo::mk_ctxt(name.to_owned())) + Some(debuginfo::DebugContext::new(llmod, name.to_owned())) } else { None }; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 87c33ce64f5..91e3276d8aa 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -11,9 +11,9 @@ use core::prelude::*; use driver::session; -use lib::llvm::ValueRef; use lib::llvm::llvm; -use middle::trans::context::task_llcx; +use lib::llvm::{ValueRef, ModuleRef, ContextRef}; +use lib::llvm::debuginfo::*; use middle::trans::common::*; use middle::trans::machine; use middle::trans::type_of; @@ -21,21 +21,18 @@ use middle::trans; use middle::ty; use util::ppaux::ty_to_str; -use core::cast; use core::hashmap::HashMap; use core::libc; -use core::option; +use core::libc::c_uint; +use core::cmp; use core::ptr; -use core::str; +use core::str::as_c_str; use core::sys; use core::vec; use syntax::codemap::span; use syntax::{ast, codemap, ast_util, ast_map}; -static LLVMDebugVersion: int = (9 << 16); - static DW_LANG_RUST: int = 0x9000; -static DW_VIRTUALITY_none: int = 0; static CompileUnitTag: int = 17; static FileDescriptorTag: int = 41; @@ -59,302 +56,169 @@ static DW_ATE_signed_char: int = 0x06; static DW_ATE_unsigned: int = 0x07; static DW_ATE_unsigned_char: int = 0x08; -fn llstr(s: &str) -> ValueRef { - do str::as_c_str(s) |sbuf| { - unsafe { - llvm::LLVMMDStringInContext(task_llcx(), - sbuf, - s.len() as libc::c_uint) - } - } -} -fn lltag(lltag: int) -> ValueRef { - lli32(LLVMDebugVersion | lltag) -} -fn lli32(val: int) -> ValueRef { - C_i32(val as i32) -} -fn lli64(val: int) -> ValueRef { - C_i64(val as i64) -} -fn lli1(bval: bool) -> ValueRef { - C_i1(bval) -} -fn llmdnode(elems: &[ValueRef]) -> ValueRef { - unsafe { - llvm::LLVMMDNodeInContext(task_llcx(), - vec::raw::to_ptr(elems), - elems.len() as libc::c_uint) - } -} -fn llunused() -> ValueRef { - lli32(0x0) -} -fn llnull() -> ValueRef { - unsafe { - cast::transmute(ptr::null::()) - } -} - -fn add_named_metadata(cx: &CrateContext, name: ~str, val: ValueRef) { - str::as_c_str(name, |sbuf| { - unsafe { - llvm::LLVMAddNamedMetadataOperand(cx.llmod, sbuf, val) - } - }) -} - //////////////// pub struct DebugContext { - llmetadata: metadata_cache, names: namegen, - crate_file: ~str + crate_file: ~str, + llcontext: ContextRef, + builder: DIBuilderRef, + curr_loc: (uint, uint), + created_files: HashMap<~str, DIFile>, + created_functions: HashMap, + created_blocks: HashMap, + created_types: HashMap } -pub fn mk_ctxt(crate: ~str) -> DebugContext { - DebugContext { - llmetadata: @mut HashMap::new(), - names: new_namegen(), - crate_file: crate +impl DebugContext { + pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext { + debug!("DebugContext::new"); + let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) }; + // DIBuilder inherits context from the module, so we'd better use the same one + let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; + return DebugContext { + names: new_namegen(), + crate_file: crate, + llcontext: llcontext, + builder: builder, + curr_loc: (0, 0), + created_files: HashMap::new(), + created_functions: HashMap::new(), + created_blocks: HashMap::new(), + created_types: HashMap::new(), + }; } } -fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) { - let mut existing = match cache.pop(&mdtag) { - Some(arr) => arr, None => ~[] - }; - existing.push(val); - cache.insert(mdtag, existing); +#[inline] +fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { + cx.dbg_cx.get_mut_ref() } -struct Metadata { - node: ValueRef, - data: T +#[inline] +fn DIB(cx: &CrateContext) -> DIBuilderRef { + cx.dbg_cx.get_ref().builder } -struct FileMetadata { - path: ~str -} -struct CompileUnitMetadata { - name: ~str -} -struct SubProgramMetadata { - id: ast::node_id -} -struct LocalVarMetadata { - id: ast::node_id -} -struct TyDescMetadata { - hash: uint -} -struct BlockMetadata { - start: codemap::Loc, - end: codemap::Loc -} -struct ArgumentMetadata { - id: ast::node_id -} -struct RetvalMetadata { - id: ast::node_id -} - -type metadata_cache = @mut HashMap; - -enum debug_metadata { - file_metadata(@Metadata), - compile_unit_metadata(@Metadata), - subprogram_metadata(@Metadata), - local_var_metadata(@Metadata), - tydesc_metadata(@Metadata), - block_metadata(@Metadata), - argument_metadata(@Metadata), - retval_metadata(@Metadata), -} - -fn cast_safely(val: T) -> U { +/// Create any deferred debug metadata nodes +pub fn finalize(cx: @mut CrateContext) { + debug!("finalize"); + create_compile_unit(cx); unsafe { - let val2 = val; - return cast::transmute(val2); - } -} - -fn md_from_metadata(val: debug_metadata) -> T { - match val { - file_metadata(md) => cast_safely(md), - compile_unit_metadata(md) => cast_safely(md), - subprogram_metadata(md) => cast_safely(md), - local_var_metadata(md) => cast_safely(md), - tydesc_metadata(md) => cast_safely(md), - block_metadata(md) => cast_safely(md), - argument_metadata(md) => cast_safely(md), - retval_metadata(md) => cast_safely(md) - } -} - -fn cached_metadata(cache: metadata_cache, - mdtag: int, - eq_fn: &fn(md: T) -> bool) - -> Option { - if cache.contains_key(&mdtag) { - let items = cache.get(&mdtag); - for items.each |item| { - let md: T = md_from_metadata::(*item); - if eq_fn(copy md) { - return option::Some(copy md); - } - } - } - return option::None; -} - -fn create_compile_unit(cx: &mut CrateContext) -> @Metadata { - let cache = get_cache(cx); - let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file; - let tg = CompileUnitTag; - match cached_metadata::<@Metadata>(cache, tg, - |md| md.data.name == crate_name) { - option::Some(md) => return md, - option::None => () - } - - let (_, work_dir) = get_file_path_and_dir( - cx.sess.working_dir.to_str(), crate_name); - let unit_metadata = ~[lltag(tg), - llunused(), - lli32(DW_LANG_RUST), - llstr(crate_name), - llstr(work_dir), - llstr(env!("CFG_VERSION")), - lli1(true), // deprecated: main compile unit - lli1(cx.sess.opts.optimize != session::No), - llstr(""), // flags (???) - lli32(0) // runtime version (???) - ]; - let unit_node = llmdnode(unit_metadata); - add_named_metadata(cx, ~"llvm.dbg.cu", unit_node); - let mdval = @Metadata { - node: unit_node, - data: CompileUnitMetadata { - name: crate_name - } + llvm::LLVMDIBuilderFinalize(DIB(cx)); + llvm::LLVMDIBuilderDispose(DIB(cx)); }; - update_cache(cache, tg, compile_unit_metadata(mdval)); - - return mdval; } -fn get_cache(cx: &CrateContext) -> metadata_cache { - cx.dbg_cx.get_ref().llmetadata +fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { + return unsafe { + llvm::LLVMDIBuilderGetOrCreateArray(builder, vec::raw::to_ptr(arr), arr.len() as u32) + }; } -fn get_file_path_and_dir(work_dir: &str, full_path: &str) -> (~str, ~str) { - (if full_path.starts_with(work_dir) { - full_path.slice(work_dir.len() + 1u, - full_path.len()).to_owned() - } else { - full_path.to_owned() - }, work_dir.to_owned()) +fn create_compile_unit(cx: @mut CrateContext) { + let dcx = dbg_cx(cx); + let crate_name: &str = dcx.crate_file; + let work_dir = cx.sess.working_dir.to_str(); + let producer = fmt!("rustc version %s", env!("CFG_VERSION")); + + do as_c_str(crate_name) |crate_name| { + do as_c_str(work_dir) |work_dir| { + do as_c_str(producer) |producer| { + do as_c_str("") |flags| { + do as_c_str("") |split_name| { unsafe { + llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder, + DW_LANG_RUST as c_uint, crate_name, work_dir, producer, + cx.sess.opts.optimize != session::No, + flags, 0, split_name); + }}}}}}; } -fn create_file(cx: &mut CrateContext, full_path: ~str) - -> @Metadata { - let cache = get_cache(cx);; - let tg = FileDescriptorTag; - match cached_metadata::<@Metadata>( - cache, tg, |md| md.data.path == full_path) { - option::Some(md) => return md, - option::None => () +fn create_file(cx: @mut CrateContext, full_path: &str) -> DIFile { + match dbg_cx(cx).created_files.find_equiv(&full_path) { + Some(file_md) => return *file_md, + None => () } - let (file_path, work_dir) = - get_file_path_and_dir(cx.sess.working_dir.to_str(), - full_path); - let unit_node = create_compile_unit(cx).node; - let file_md = ~[lltag(tg), - llstr(file_path), - llstr(work_dir), - unit_node]; - let val = llmdnode(file_md); - let mdval = @Metadata { - node: val, - data: FileMetadata { - path: full_path - } - }; - update_cache(cache, tg, file_metadata(mdval)); - return mdval; + debug!("create_file: %s", full_path); + + let work_dir = cx.sess.working_dir.to_str(); + let file_name = + if full_path.starts_with(work_dir) { + full_path.slice(work_dir.len() + 1u, full_path.len()) + } else { + full_path + }; + + let file_md = + do as_c_str(file_name) |file_name| { + do as_c_str(work_dir) |work_dir| { unsafe { + llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir) + }}}; + + dbg_cx(cx).created_files.insert(full_path.to_owned(), file_md); + return file_md; } -fn line_from_span(cm: @codemap::CodeMap, sp: span) -> uint { - cm.lookup_char_pos(sp.lo).line +/// Return codemap::Loc corresponding to the beginning of the span +fn span_start(cx: &CrateContext, span: span) -> codemap::Loc { + return cx.sess.codemap.lookup_char_pos(span.lo); } -fn create_block(mut cx: block) -> @Metadata { - let cache = get_cache(cx.ccx()); - while cx.node_info.is_none() { - match cx.parent { - Some(b) => cx = b, +fn create_block(bcx: block) -> DILexicalBlock { + let mut bcx = bcx; + let cx = bcx.ccx(); + + while bcx.node_info.is_none() { + match bcx.parent { + Some(b) => bcx = b, None => fail!() } } - let sp = cx.node_info.get().span; + let span = bcx.node_info.get().span; + let id = bcx.node_info.get().id; - let start = cx.sess().codemap.lookup_char_pos(sp.lo); - let fname = /*bad*/copy start.file.name; - let end = cx.sess().codemap.lookup_char_pos(sp.hi); - let tg = LexicalBlockTag; - /*match cached_metadata::<@Metadata>( - cache, tg, - {|md| start == md.data.start && end == md.data.end}) { - option::Some(md) { return md; } - option::None {} - }*/ - - let parent = match cx.parent { - None => create_function(cx.fcx).node, - Some(bcx) => create_block(bcx).node - }; - let file_node = create_file(cx.ccx(), /* bad */ fname.to_owned()); - let unique_id = match cache.find(&LexicalBlockTag) { - option::Some(v) => v.len() as int, - option::None => 0 - }; - let lldata = ~[lltag(tg), - parent, - lli32(start.line.to_int()), - lli32(start.col.to_int()), - file_node.node, - lli32(unique_id) - ]; - let val = llmdnode(lldata); - let mdval = @Metadata { - node: val, - data: BlockMetadata { - start: start, - end: end - } - }; - //update_cache(cache, tg, block_metadata(mdval)); - return mdval; -} - -fn size_and_align_of(cx: &mut CrateContext, t: ty::t) -> (int, int) { - let llty = type_of::type_of(cx, t); - (machine::llsize_of_real(cx, llty) as int, - machine::llalign_of_pref(cx, llty) as int) -} - -fn create_basic_type(cx: &mut CrateContext, t: ty::t, span: span) - -> @Metadata { - let cache = get_cache(cx); - let tg = BasicTypeDescriptorTag; - match cached_metadata::<@Metadata>( - cache, tg, |md| ty::type_id(t) == md.data.hash) { - option::Some(md) => return md, - option::None => () + match dbg_cx(cx).created_blocks.find(&id) { + Some(block) => return *block, + None => () } + debug!("create_block: %s", bcx.sess().codemap.span_to_str(span)); + + let parent = match bcx.parent { + None => create_function(bcx.fcx), + Some(b) => create_block(b) + }; + let cx = bcx.ccx(); + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); + + let block_md = unsafe { + llvm::LLVMDIBuilderCreateLexicalBlock( + DIB(cx), + parent, file_md, + loc.line as c_uint, loc.col.to_uint() as c_uint) + }; + + dbg_cx(cx).created_blocks.insert(id, block_md); + + return block_md; +} + +fn size_and_align_of(cx: @mut CrateContext, t: ty::t) -> (uint, uint) { + let llty = type_of::type_of(cx, t); + (machine::llsize_of_real(cx, llty), machine::llalign_of_min(cx, llty)) +} + +fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType { + let ty_id = ty::type_id(t); + match dbg_cx(cx).created_types.find(&ty_id) { + Some(ty_md) => return *ty_md, + None => () + } + + debug!("create_basic_type: %?", ty::get(t)); + let (name, encoding) = match ty::get(t).sty { ty::ty_nil | ty::ty_bot => (~"uint", DW_ATE_unsigned), ty::ty_bool => (~"bool", DW_ATE_boolean), @@ -378,383 +242,275 @@ fn create_basic_type(cx: &mut CrateContext, t: ty::t, span: span) ast::ty_f32 => (~"f32", DW_ATE_float), ast::ty_f64 => (~"f64", DW_ATE_float) }, - _ => cx.sess.bug("debuginfo::create_basic_type - t is invalid type") + _ => cx.sess.bug(~"debuginfo::create_basic_type - t is invalid type") }; - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let cu_node = create_compile_unit(cx); let (size, align) = size_and_align_of(cx, t); - let lldata = ~[lltag(tg), - cu_node.node, - llstr(name), - file_node.node, - lli32(0), //XXX source line - lli64(size * 8), // size in bits - lli64(align * 8), // alignment in bits - lli64(0), //XXX offset? - lli32(0), //XXX flags? - lli32(encoding)]; - let llnode = llmdnode(lldata); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, ~"llvm.dbg.ty", llnode); - return mdval; + let ty_md = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), name, + size * 8 as u64, align * 8 as u64, encoding as c_uint) + }}; + + dbg_cx(cx).created_types.insert(ty_id, ty_md); + return ty_md; } -fn create_pointer_type(cx: &mut CrateContext, t: ty::t, span: span, - pointee: @Metadata) - -> @Metadata { - let tg = PointerTypeTag; - /*let cache = cx.llmetadata; - match cached_metadata::<@Metadata>( - cache, tg, {|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) { - option::Some(md) { return md; } - option::None {} - }*/ +fn create_pointer_type(cx: @mut CrateContext, t: ty::t, _span: span, pointee: DIType) -> DIType { let (size, align) = size_and_align_of(cx, t); - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - //let cu_node = create_compile_unit(cx, fname); let name = ty_to_str(cx.tcx, t); - let llnode = create_derived_type(tg, file_node.node, name, 0, size * 8, - align * 8, 0, pointee.node); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - //update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, ~"llvm.dbg.ty", llnode); - return mdval; + let ptr_md = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreatePointerType(DIB(cx), + pointee, size * 8 as u64, align * 8 as u64, name) + }}; + return ptr_md; } -struct StructCtxt { - file: ValueRef, - name: @str, - line: int, - members: ~[ValueRef], - total_size: int, - align: int +struct StructContext { + builder: DIBuilderRef, + file: DIFile, + name: ~str, + line: uint, + members: ~[DIDerivedType], + total_size: uint, + align: uint } -fn finish_structure(cx: @mut StructCtxt) -> ValueRef { - return create_composite_type(StructureTypeTag, - cx.name, - cx.file, - cx.line, - cx.total_size, - cx.align, - 0, - None, - Some(/*bad*/copy cx.members)); +impl StructContext { + fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> ~StructContext { + debug!("StructContext::create: %s", name); + let scx = ~StructContext { + builder: DIB(cx), + file: file, + name: name, + line: line, + members: ~[], + total_size: 0, + align: 1 + }; + return scx; + } + + fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) { + debug!("StructContext(%s)::add_member: %s, size=%u, align=%u", + self.name, name, size, align); + let offset = roundup(self.total_size, align); + let mem_t = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateMemberType( + self.builder, ptr::null(), name, self.file, line as c_uint, + size * 8 as u64, align * 8 as u64, offset * 8 as u64, + 0, ty) + }}; + self.members.push(mem_t); + self.total_size = offset + size; + // struct alignment is the max alignment of its' members + self.align = cmp::max(self.align, align); + } + + fn finalize(&self) -> DICompositeType { + debug!("StructContext(%s)::finalize: total_size=%u, align=%u", + self.name, self.total_size, self.align); + let members_md = create_DIArray(self.builder, self.members); + + let struct_md = + do as_c_str(self.name) |name| { unsafe { + llvm::LLVMDIBuilderCreateStructType( + self.builder, self.file, name, + self.file, self.line as c_uint, + self.total_size * 8 as u64, self.align * 8 as u64, 0, ptr::null(), + members_md, 0, ptr::null()) + }}; + return struct_md; + } } -fn create_structure(file: @Metadata, name: @str, line: int) - -> @mut StructCtxt { - let cx = @mut StructCtxt { - file: file.node, - name: name, - line: line, - members: ~[], - total_size: 0, - align: 64 //XXX different alignment per arch? - }; - return cx; +#[inline] +fn roundup(x: uint, a: uint) -> uint { + ((x + (a - 1)) / a) * a } -fn create_derived_type(type_tag: int, file: ValueRef, name: &str, line: int, - size: int, align: int, offset: int, ty: ValueRef) - -> ValueRef { - let lldata = ~[lltag(type_tag), - file, - llstr(name), - file, - lli32(line), - lli64(size), - lli64(align), - lli64(offset), - lli32(0), - ty]; - return llmdnode(lldata); -} +fn create_struct(cx: @mut CrateContext, t: ty::t, fields: ~[ty::field], span: span) + -> DICompositeType { + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); -fn add_member(cx: @mut StructCtxt, - name: &str, - line: int, - size: int, - align: int, - ty: ValueRef) { - cx.members.push(create_derived_type(MemberTag, cx.file, name, line, - size * 8, align * 8, cx.total_size, - ty)); - cx.total_size += size * 8; -} - -fn create_struct(cx: &mut CrateContext, t: ty::t, fields: ~[ty::field], - span: span) -> @Metadata { - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let scx = create_structure(file_node, (ty_to_str(cx.tcx, t)).to_managed(), - line_from_span(cx.sess.codemap, span) as int); + let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, t), file_md, loc.line); for fields.each |field| { let field_t = field.mt.ty; let ty_md = create_ty(cx, field_t, span); let (size, align) = size_and_align_of(cx, field_t); - add_member(scx, cx.sess.str_of(field.ident), - line_from_span(cx.sess.codemap, span) as int, - size as int, align as int, ty_md.node); + scx.add_member(cx.sess.str_of(field.ident), loc.line, size, align, ty_md); } - let mdval = @Metadata { - node: finish_structure(scx), - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - return mdval; -} - -fn create_tuple(cx: &mut CrateContext, t: ty::t, elements: &[ty::t], span: span) - -> @Metadata { - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let scx = create_structure(file_node, - cx.sess.str_of( - ((/*bad*/copy cx.dbg_cx).get().names) - ("tuple")), - line_from_span(cx.sess.codemap, span) as int); - for elements.each |element| { - let ty_md = create_ty(cx, *element, span); - let (size, align) = size_and_align_of(cx, *element); - add_member(scx, "", line_from_span(cx.sess.codemap, span) as int, - size as int, align as int, ty_md.node); - } - let mdval = @Metadata { - node: finish_structure(scx), - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - return mdval; + return scx.finalize(); } // returns (void* type as a ValueRef, size in bytes, align in bytes) -fn voidptr() -> (ValueRef, int, int) { - let null = ptr::null(); - let size = sys::size_of::() as int; - let align = sys::min_align_of::() as int; - let vp = create_derived_type(PointerTypeTag, null, "", 0, - size, align, 0, null); +fn voidptr(cx: @mut CrateContext) -> (DIDerivedType, uint, uint) { + let size = sys::size_of::(); + let align = sys::min_align_of::(); + let vp = do as_c_str("*void") |name| { unsafe { + llvm::LLVMDIBuilderCreatePointerType(DIB(cx), ptr::null(), + size*8 as u64, align*8 as u64, name) + }}; return (vp, size, align); } -fn create_boxed_type(cx: &mut CrateContext, contents: ty::t, - span: span, boxed: @Metadata) - -> @Metadata { - //let tg = StructureTypeTag; - /*let cache = cx.llmetadata; - match cached_metadata::<@Metadata>( - cache, tg, {|md| ty::hash_ty(contents) == ty::hash_ty(md.data.hash)}) { - option::Some(md) { return md; } - option::None {} - }*/ - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - //let cu_node = create_compile_unit_metadata(cx, fname); +fn create_tuple(cx: @mut CrateContext, _t: ty::t, elements: &[ty::t], span: span) + -> DICompositeType { + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); + + let name = (cx.sess.str_of((dbg_cx(cx).names)("tuple"))).to_owned(); + let mut scx = StructContext::new(cx, name, file_md, loc.line); + for elements.each |element| { + let ty_md = create_ty(cx, *element, span); + let (size, align) = size_and_align_of(cx, *element); + scx.add_member("", loc.line, size, align, ty_md); + } + return scx.finalize(); +} + +fn create_boxed_type(cx: @mut CrateContext, contents: ty::t, + span: span, boxed: DIType) -> DICompositeType { + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); let int_t = ty::mk_int(); let refcount_type = create_basic_type(cx, int_t, span); let name = ty_to_str(cx.tcx, contents); - let scx = create_structure(file_node, (fmt!("box<%s>", name)).to_managed(), 0); - add_member(scx, "refcnt", 0, sys::size_of::() as int, - sys::min_align_of::() as int, refcount_type.node); + + let mut scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0); + scx.add_member("refcnt", 0, sys::size_of::(), + sys::min_align_of::(), refcount_type); // the tydesc and other pointers should be irrelevant to the // debugger, so treat them as void* types - let (vp, vpsize, vpalign) = voidptr(); - add_member(scx, "tydesc", 0, vpsize, vpalign, vp); - add_member(scx, "prev", 0, vpsize, vpalign, vp); - add_member(scx, "next", 0, vpsize, vpalign, vp); + let (vp, vpsize, vpalign) = voidptr(cx); + scx.add_member("tydesc", 0, vpsize, vpalign, vp); + scx.add_member("prev", 0, vpsize, vpalign, vp); + scx.add_member("next", 0, vpsize, vpalign, vp); let (size, align) = size_and_align_of(cx, contents); - add_member(scx, "boxed", 0, size, align, boxed.node); - let llnode = finish_structure(scx); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(contents) - } - }; - //update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, ~"llvm.dbg.ty", llnode); - return mdval; + scx.add_member("boxed", 0, size, align, boxed); + return scx.finalize(); } -fn create_composite_type(type_tag: int, name: &str, file: ValueRef, - line: int, size: int, align: int, offset: int, - derived: Option, - members: Option<~[ValueRef]>) - -> ValueRef { - let lldata = ~[lltag(type_tag), - file, - llstr(name), // type name - file, // source file definition - lli32(line), // source line definition - lli64(size), // size of members - lli64(align), // align - lli32/*64*/(offset), // offset - lli32(0), // flags - if derived.is_none() { - llnull() - } else { // derived from - derived.get() - }, - if members.is_none() { - llnull() - } else { //members - llmdnode(members.get()) - }, - lli32(0), // runtime language - llnull() - ]; - return llmdnode(lldata); -} - -fn create_fixed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, - len: int, span: span) -> @Metadata { - let t_md = create_ty(cx, elem_t, span); - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); +fn create_fixed_vec(cx: @mut CrateContext, _vec_t: ty::t, elem_t: ty::t, + len: uint, span: span) -> DIType { + let elem_ty_md = create_ty(cx, elem_t, span); let (size, align) = size_and_align_of(cx, elem_t); - let subrange = llmdnode([lltag(SubrangeTag), lli64(0), lli64(len - 1)]); - let name = fmt!("[%s]", ty_to_str(cx.tcx, elem_t)); - let array = create_composite_type(ArrayTypeTag, name, file_node.node, 0, - size * len, align, 0, Some(t_md.node), - Some(~[subrange])); - @Metadata { - node: array, - data: TyDescMetadata { - hash: ty::type_id(vec_t) - } - } + + let subrange = unsafe { + llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, len as i64) + }; + + let subscripts = create_DIArray(DIB(cx), [subrange]); + return unsafe { + llvm::LLVMDIBuilderCreateArrayType(DIB(cx), + size * len * 8 as u64, align * 8 as u64, elem_ty_md, subscripts) + }; } -fn create_boxed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, - vec_ty_span: codemap::span) - -> @Metadata { - let fname = filename_from_span(cx, vec_ty_span); - let file_node = create_file(cx, fname.to_owned()); +fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, + vec_ty_span: span) -> DICompositeType { + let loc = span_start(cx, vec_ty_span); + let file_md = create_file(cx, loc.file.name); let elem_ty_md = create_ty(cx, elem_t, vec_ty_span); - let vec_scx = create_structure(file_node, - ty_to_str(cx.tcx, vec_t).to_managed(), 0); + + let mut vec_scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0); let size_t_type = create_basic_type(cx, ty::mk_uint(), vec_ty_span); - add_member(vec_scx, "fill", 0, sys::size_of::() as int, - sys::min_align_of::() as int, size_t_type.node); - add_member(vec_scx, "alloc", 0, sys::size_of::() as int, - sys::min_align_of::() as int, size_t_type.node); - let subrange = llmdnode([lltag(SubrangeTag), lli64(0), lli64(0)]); + vec_scx.add_member("fill", 0, sys::size_of::(), + sys::min_align_of::(), size_t_type); + vec_scx.add_member("alloc", 0, sys::size_of::(), + sys::min_align_of::(), size_t_type); + let subrange = unsafe { + llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, 0_i64) + }; let (arr_size, arr_align) = size_and_align_of(cx, elem_t); let name = fmt!("[%s]", ty_to_str(cx.tcx, elem_t)); - let data_ptr = create_composite_type(ArrayTypeTag, name, file_node.node, 0, - arr_size, arr_align, 0, - Some(elem_ty_md.node), - Some(~[subrange])); - add_member(vec_scx, "data", 0, 0, // clang says the size should be 0 - sys::min_align_of::() as int, data_ptr); - let llnode = finish_structure(vec_scx); - let vec_md = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(vec_t) - } - }; - let box_scx = create_structure(file_node, (fmt!("box<%s>", name)).to_managed(), 0); + let subscripts = create_DIArray(DIB(cx), [subrange]); + let data_ptr = unsafe { + llvm::LLVMDIBuilderCreateArrayType(DIB(cx), + arr_size * 8 as u64, arr_align * 8 as u64, elem_ty_md, subscripts) + }; + vec_scx.add_member("data", 0, 0, // clang says the size should be 0 + sys::min_align_of::(), data_ptr); + let vec_md = vec_scx.finalize(); + + let mut box_scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0); let int_t = ty::mk_int(); let refcount_type = create_basic_type(cx, int_t, vec_ty_span); - add_member(box_scx, "refcnt", 0, sys::size_of::() as int, - sys::min_align_of::() as int, refcount_type.node); - let (vp, vpsize, vpalign) = voidptr(); - add_member(box_scx, "tydesc", 0, vpsize, vpalign, vp); - add_member(box_scx, "prev", 0, vpsize, vpalign, vp); - add_member(box_scx, "next", 0, vpsize, vpalign, vp); - let size = 2 * sys::size_of::() as int; - let align = sys::min_align_of::() as int; - add_member(box_scx, "boxed", 0, size, align, vec_md.node); - let llnode = finish_structure(box_scx); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(elem_t) - } - }; + box_scx.add_member("refcnt", 0, sys::size_of::(), + sys::min_align_of::(), refcount_type); + let (vp, vpsize, vpalign) = voidptr(cx); + box_scx.add_member("tydesc", 0, vpsize, vpalign, vp); + box_scx.add_member("prev", 0, vpsize, vpalign, vp); + box_scx.add_member("next", 0, vpsize, vpalign, vp); + let size = 2 * sys::size_of::(); + let align = sys::min_align_of::(); + box_scx.add_member("boxed", 0, size, align, vec_md); + let mdval = box_scx.finalize(); return mdval; } -fn create_vec_slice(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) - -> @Metadata { - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); +fn create_vec_slice(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) + -> DICompositeType { + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); let elem_ty_md = create_ty(cx, elem_t, span); let uint_type = create_basic_type(cx, ty::mk_uint(), span); let elem_ptr = create_pointer_type(cx, elem_t, span, elem_ty_md); - let scx = create_structure(file_node, ty_to_str(cx.tcx, vec_t).to_managed(), 0); - let (_, ptr_size, ptr_align) = voidptr(); - add_member(scx, "vec", 0, ptr_size, ptr_align, elem_ptr.node); - add_member(scx, "length", 0, sys::size_of::() as int, - sys::min_align_of::() as int, uint_type.node); - let llnode = finish_structure(scx); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(vec_t) - } - }; - return mdval; + + let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0); + let (_, ptr_size, ptr_align) = voidptr(cx); + scx.add_member("vec", 0, ptr_size, ptr_align, elem_ptr); + scx.add_member("length", 0, sys::size_of::(), + sys::min_align_of::(), uint_type); + return scx.finalize(); } -fn create_fn_ty(cx: &mut CrateContext, fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, - span: span) -> @Metadata { - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let (vp, _, _) = voidptr(); +fn create_fn_ty(cx: @mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, + span: span) -> DICompositeType { + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); + let (vp, _, _) = voidptr(cx); let output_md = create_ty(cx, output, span); let output_ptr_md = create_pointer_type(cx, output, span, output_md); - let inputs_vals = do inputs.map |arg| { create_ty(cx, *arg, span).node }; - let members = ~[output_ptr_md.node, vp] + inputs_vals; - let llnode = create_composite_type(SubroutineTag, "", file_node.node, - 0, 0, 0, 0, None, Some(members)); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(fn_ty) - } + let inputs_vals = do inputs.map |arg| { create_ty(cx, *arg, span) }; + let members = ~[output_ptr_md, vp] + inputs_vals; + + return unsafe { + llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_md, + create_DIArray(DIB(cx), members)) }; - return mdval; } -fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) - -> @Metadata { +fn create_unimpl_ty(cx: @mut CrateContext, t: ty::t) -> DIType { + let name = ty_to_str(cx.tcx, t); + let md = do as_c_str(fmt!("NYI<%s>", name)) |name| { unsafe { + llvm::LLVMDIBuilderCreateBasicType( + DIB(cx), name, + 0_u64, 8_u64, DW_ATE_unsigned as c_uint) + }}; + return md; +} + +fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType { + let ty_id = ty::type_id(t); + match dbg_cx(cx).created_types.find(&ty_id) { + Some(ty_md) => return *ty_md, + None => () + } + debug!("create_ty: %?", ty::get(t)); - /*let cache = get_cache(cx); - match cached_metadata::<@Metadata>( - cache, tg, {|md| t == md.data.hash}) { - option::Some(md) { return md; } - option::None {} - }*/ let sty = copy ty::get(t).sty; - match sty { + let ty_md = match sty { ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) => create_basic_type(cx, t, span), ty::ty_estr(ref vstore) => { let i8_t = ty::mk_i8(); match *vstore { ty::vstore_fixed(len) => { - create_fixed_vec(cx, t, i8_t, len as int + 1, span) + create_fixed_vec(cx, t, i8_t, len + 1, span) }, ty::vstore_uniq | ty::vstore_box => { let box_md = create_boxed_vec(cx, t, i8_t, span); @@ -766,7 +522,8 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) } }, ty::ty_enum(_did, ref _substs) => { - cx.sess.span_bug(span, "debuginfo for enum NYI") + cx.sess.span_note(span, "debuginfo for enum NYI"); + create_unimpl_ty(cx, t) } ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => { let boxed = create_ty(cx, mt.ty, span); @@ -776,7 +533,7 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) ty::ty_evec(ref mt, ref vstore) => { match *vstore { ty::vstore_fixed(len) => { - create_fixed_vec(cx, t, mt.ty, len as int, span) + create_fixed_vec(cx, t, mt.ty, len, span) }, ty::vstore_uniq | ty::vstore_box => { let box_md = create_boxed_vec(cx, t, mt.ty, span); @@ -792,7 +549,8 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) create_pointer_type(cx, t, span, pointee) }, ty::ty_rptr(ref _region, ref _mt) => { - cx.sess.span_bug(span, "debuginfo for rptr NYI") + cx.sess.span_note(span, "debuginfo for rptr NYI"); + create_unimpl_ty(cx, t) }, ty::ty_bare_fn(ref barefnty) => { let inputs = barefnty.sig.inputs.map(|a| *a); @@ -800,10 +558,12 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) create_fn_ty(cx, t, inputs, output, span) }, ty::ty_closure(ref _closurety) => { - cx.sess.span_bug(span, "debuginfo for closure NYI") + cx.sess.span_note(span, "debuginfo for closure NYI"); + create_unimpl_ty(cx, t) }, ty::ty_trait(_did, ref _substs, ref _vstore, _) => { - cx.sess.span_bug(span, "debuginfo for trait NYI") + cx.sess.span_note(span, "debuginfo for trait NYI"); + create_unimpl_ty(cx, t) }, ty::ty_struct(did, ref substs) => { let fields = ty::struct_fields(cx.tcx, did, substs); @@ -812,60 +572,42 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) ty::ty_tup(ref elements) => { create_tuple(cx, t, *elements, span) }, - _ => cx.sess.bug("debuginfo: unexpected type in create_ty") - } + _ => cx.sess.bug(~"debuginfo: unexpected type in create_ty") + }; + + dbg_cx(cx).created_types.insert(ty_id, ty_md); + return ty_md; } -fn filename_from_span(cx: &CrateContext, sp: codemap::span) -> @str { - cx.sess.codemap.lookup_char_pos(sp.lo).file.name -} - -fn create_var(type_tag: int, context: ValueRef, name: &str, file: ValueRef, - line: int, ret_ty: ValueRef) -> ValueRef { - let lldata = ~[lltag(type_tag), - context, - llstr(name), - file, - lli32(line), - ret_ty, - lli32(0) - ]; - return llmdnode(lldata); -} - -pub fn create_local_var(bcx: block, local: @ast::local) - -> @Metadata { +pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { let cx = bcx.ccx(); - let cache = get_cache(cx); - let tg = AutoVariableTag; - match cached_metadata::<@Metadata>( - cache, tg, |md| md.data.id == local.node.id) { - option::Some(md) => return md, - option::None => () - } - let name = match local.node.pat.node { + let ident = match local.node.pat.node { ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth), // FIXME this should be handled (#2533) - _ => fail!("no single variable name for local") + _ => { + bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI"); + return ptr::null(); + } }; - let loc = cx.sess.codemap.lookup_char_pos(local.span.lo); + let name: &str = cx.sess.str_of(ident); + debug!("create_local_var: %s", name); + + let loc = span_start(cx, local.span); let ty = node_id_type(bcx, local.node.id); let tymd = create_ty(cx, ty, local.node.ty.span); - let filemd = create_file(cx, /*bad*/ loc.file.name.to_owned()); + let filemd = create_file(cx, loc.file.name); let context = match bcx.parent { - None => create_function(bcx.fcx).node, - Some(_) => create_block(bcx).node + None => create_function(bcx.fcx), + Some(_) => create_block(bcx) }; - let mdnode = create_var(tg, context, cx.sess.str_of(name), - filemd.node, loc.line as int, tymd.node); - let mdval = @Metadata { - node: mdnode, - data: LocalVarMetadata { - id: local.node.id - } - }; - update_cache(cache, AutoVariableTag, local_var_metadata(mdval)); + + let var_md = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), AutoVariableTag as u32, + context, name, filemd, + loc.line as c_uint, tymd, false, 0, 0) + }}; // FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc let llptr = match bcx.fcx.lllocals.find_copy(&local.node.pat.id) { @@ -876,59 +618,57 @@ pub fn create_local_var(bcx: block, local: @ast::local) fmt!("No entry in lllocals table for %?", local.node.id)); } }; - let declargs = ~[llmdnode([llptr]), mdnode]; - trans::build::Call(bcx, cx.intrinsics.get_copy(&("llvm.dbg.declare")), - declargs); - return mdval; -} -pub fn create_arg(bcx: block, arg: ast::arg, sp: span) - -> Option<@Metadata> { - let fcx = bcx.fcx; - let cx = fcx.ccx; - let cache = get_cache(cx); - let tg = ArgVariableTag; - match cached_metadata::<@Metadata>( - cache, ArgVariableTag, |md| md.data.id == arg.id) { - option::Some(md) => return Some(md), - option::None => () + set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); + unsafe { + let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_md, bcx.llbb); + llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); } - let loc = cx.sess.codemap.lookup_char_pos(sp.lo); + return var_md; +} + +pub fn create_arg(bcx: block, arg: ast::arg, span: span) -> Option { + debug!("create_arg"); + if true { + // XXX create_arg disabled for now because "node_id_type(bcx, arg.id)" below blows + // up: "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`" + return None; + } + + let fcx = bcx.fcx; + let cx = fcx.ccx; + + let loc = span_start(cx, span); if "" == loc.file.name { return None; } + let ty = node_id_type(bcx, arg.id); let tymd = create_ty(cx, ty, arg.ty.span); - let filemd = create_file(cx, /* bad */ loc.file.name.to_owned()); - let context = create_function(bcx.fcx); + let filemd = create_file(cx, loc.file.name); + let context = create_function(fcx); match arg.pat.node { ast::pat_ident(_, path, _) => { // XXX: This is wrong; it should work for multiple bindings. - let mdnode = create_var( - tg, - context.node, - cx.sess.str_of(*path.idents.last()), - filemd.node, - loc.line as int, - tymd.node - ); - - let mdval = @Metadata { - node: mdnode, - data: ArgumentMetadata { - id: arg.id - } - }; - update_cache(cache, tg, argument_metadata(mdval)); + let ident = path.idents.last(); + let name: &str = cx.sess.str_of(*ident); + let mdnode = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateLocalVariable(DIB(cx), + ArgVariableTag as u32, context, name, + filemd, loc.line as c_uint, tymd, false, 0, 0) + // XXX need to pass in a real argument number + }}; let llptr = fcx.llargs.get_copy(&arg.id); - let declargs = ~[llmdnode([llptr]), mdnode]; - trans::build::Call(bcx, - cx.intrinsics.get_copy(&("llvm.dbg.declare")), - declargs); - return Some(mdval); + set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); + unsafe { + let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( + DIB(cx), llptr, mdnode, bcx.llbb); + llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); + } + return Some(mdnode); } _ => { return None; @@ -936,32 +676,36 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span) } } -pub fn update_source_pos(cx: block, s: span) { - if !cx.sess().opts.debuginfo || (*s.lo == 0 && *s.hi == 0) { +fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) { + if dbg_cx(cx).curr_loc == (line, col) { return; } - let cm = cx.sess().codemap; - let blockmd = create_block(cx); - let loc = cm.lookup_char_pos(s.lo); - let scopedata = ~[lli32(loc.line.to_int()), - lli32(loc.col.to_int()), - blockmd.node, - llnull()]; - let dbgscope = llmdnode(scopedata); + debug!("setting debug location to %u %u", line, col); + dbg_cx(cx).curr_loc = (line, col); + + let elems = ~[C_i32(line as i32), C_i32(col as i32), scope, ptr::null()]; unsafe { - llvm::LLVMSetCurrentDebugLocation(trans::build::B(cx), dbgscope); + let dbg_loc = llvm::LLVMMDNodeInContext( + dbg_cx(cx).llcontext, vec::raw::to_ptr(elems), + elems.len() as libc::c_uint); + llvm::LLVMSetCurrentDebugLocation(cx.builder.B, dbg_loc); } } -pub fn create_function(fcx: fn_ctxt) -> @Metadata { - let mut cx = fcx.ccx; - - debug!("~~"); +/// Set current debug location at the beginning of the span +pub fn update_source_pos(bcx: block, span: span) { + if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) { + return; + } + debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span)); + let loc = span_start(bcx.ccx(), span); + set_debug_location(bcx.ccx(), create_block(bcx), loc.line, loc.col.to_uint()) +} +pub fn create_function(fcx: fn_ctxt) -> DISubprogram { + let cx = fcx.ccx; let fcx = &mut *fcx; - - let sp = fcx.span.get(); - debug!("%s", cx.sess.codemap.span_to_str(sp)); + let span = fcx.span.get(); let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) { ast_map::node_item(item, _) => { @@ -978,8 +722,7 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { ast_map::node_expr(expr) => { match expr.node { ast::expr_fn_block(ref decl, _) => { - let dbg_cx = cx.dbg_cx.get_ref(); - ((dbg_cx.names)("fn"), decl.output, expr.id) + ((dbg_cx(cx).names)("fn"), decl.output, expr.id) } _ => fcx.ccx.sess.span_bug(expr.span, "create_function: expected an expr_fn_block here") @@ -988,62 +731,46 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") }; - debug!("%?", ident); - debug!("%?", id); - - let cache = get_cache(cx); - match cached_metadata::<@Metadata>( - cache, SubprogramTag, |md| md.data.id == id) { - option::Some(md) => return md, - option::None => () + match dbg_cx(cx).created_functions.find(&id) { + Some(fn_md) => return *fn_md, + None => () } - let loc = cx.sess.codemap.lookup_char_pos(sp.lo); - let file_node = create_file(cx, loc.file.name.to_owned()).node; - let ty_node = if cx.sess.opts.extra_debuginfo { + debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span)); + + let loc = span_start(cx, span); + let file_md = create_file(cx, loc.file.name); + + let ret_ty_md = if cx.sess.opts.extra_debuginfo { match ret_ty.node { - ast::ty_nil => llnull(), + ast::ty_nil => ptr::null(), _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), - ret_ty.span).node + ret_ty.span) } } else { - llnull() + ptr::null() }; - let sub_node = create_composite_type(SubroutineTag, "", file_node, 0, 0, - 0, 0, option::None, - option::Some(~[ty_node])); - let fn_metadata = ~[lltag(SubprogramTag), - llunused(), - file_node, - llstr(cx.sess.str_of(ident)), - //XXX fully-qualified C++ name: - llstr(cx.sess.str_of(ident)), - llstr(""), //XXX MIPS name????? - file_node, - lli32(loc.line as int), - sub_node, - lli1(false), //XXX static (check export) - lli1(true), // defined in compilation unit - lli32(DW_VIRTUALITY_none), // virtual-ness - lli32(0i), //index into virt func - /*llnull()*/ lli32(0), // base type with vtbl - lli32(256), // flags - lli1(cx.sess.opts.optimize != session::No), - fcx.llfn - //list of template params - //func decl descriptor - //list of func vars - ]; - let val = llmdnode(fn_metadata); - add_named_metadata(cx, ~"llvm.dbg.sp", val); - let mdval = @Metadata { - node: val, - data: SubProgramMetadata { - id: id - } + let fn_ty = unsafe { + llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), + file_md, create_DIArray(DIB(cx), [ret_ty_md])) }; - update_cache(cache, SubprogramTag, subprogram_metadata(mdval)); - return mdval; + let fn_md = + do as_c_str(cx.sess.str_of(ident)) |name| { + do as_c_str(cx.sess.str_of(ident)) |linkage| { unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + file_md, + name, linkage, + file_md, loc.line as c_uint, + fn_ty, false, true, + loc.line as c_uint, + FlagPrototyped as c_uint, + cx.sess.opts.optimize != session::No, + fcx.llfn, ptr::null(), ptr::null()) + }}}; + + dbg_cx(cx).created_functions.insert(id, fn_md); + return fn_md; } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index ba87624e2dd..614c1723c5f 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -560,3 +560,228 @@ extern "C" bool LLVMRustStartMultithreading() { assert(lock.release()); return ret; } + + +typedef DIBuilder* DIBuilderRef; + +template +DIT unwrapDI(LLVMValueRef ref) { + return DIT(ref ? unwrap(ref) : NULL); +} + +extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) { + return new DIBuilder(*unwrap(M)); +} + +extern "C" void LLVMDIBuilderDispose(DIBuilderRef Builder) { + delete Builder; +} + +extern "C" void LLVMDIBuilderFinalize(DIBuilderRef Builder) { + Builder->finalize(); +} + +extern "C" void LLVMDIBuilderCreateCompileUnit( + DIBuilderRef Builder, + unsigned Lang, + const char* File, + const char* Dir, + const char* Producer, + bool isOptimized, + const char* Flags, + unsigned RuntimeVer, + const char* SplitName) { + Builder->createCompileUnit(Lang, File, Dir, Producer, isOptimized, + Flags, RuntimeVer, SplitName); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateFile( + DIBuilderRef Builder, + const char* Filename, + const char* Directory) { + return wrap(Builder->createFile(Filename, Directory)); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType( + DIBuilderRef Builder, + LLVMValueRef File, + LLVMValueRef ParameterTypes) { + return wrap(Builder->createSubroutineType( + unwrapDI(File), + unwrapDI(ParameterTypes))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateFunction( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + const char* LinkageName, + LLVMValueRef File, + unsigned LineNo, + LLVMValueRef Ty, + bool isLocalToUnit, + bool isDefinition, + unsigned ScopeLine, + unsigned Flags, + bool isOptimized, + LLVMValueRef Fn, + LLVMValueRef TParam, + LLVMValueRef Decl) { + return wrap(Builder->createFunction( + unwrapDI(Scope), Name, LinkageName, + unwrapDI(File), LineNo, + unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, + Flags, isOptimized, + unwrap(Fn), + unwrapDI(TParam), + unwrapDI(Decl))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateBasicType( + DIBuilderRef Builder, + const char* Name, + uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Encoding) { + return wrap(Builder->createBasicType( + Name, SizeInBits, + AlignInBits, Encoding)); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType( + DIBuilderRef Builder, + LLVMValueRef PointeeTy, + uint64_t SizeInBits, + uint64_t AlignInBits, + const char* Name) { + return wrap(Builder->createPointerType( + unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateStructType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Flags, + LLVMValueRef DerivedFrom, + LLVMValueRef Elements, + unsigned RunTimeLang, + LLVMValueRef VTableHolder) { + return wrap(Builder->createStructType( + unwrapDI(Scope), Name, + unwrapDI(File), LineNumber, + SizeInBits, AlignInBits, Flags, + unwrapDI(DerivedFrom), + unwrapDI(Elements), RunTimeLang, + unwrapDI(VTableHolder))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNo, + uint64_t SizeInBits, + uint64_t AlignInBits, + uint64_t OffsetInBits, + unsigned Flags, + LLVMValueRef Ty) { + return wrap(Builder->createMemberType( + unwrapDI(Scope), Name, + unwrapDI(File), LineNo, + SizeInBits, AlignInBits, OffsetInBits, Flags, + unwrapDI(Ty))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( + DIBuilderRef Builder, + LLVMValueRef Scope, + LLVMValueRef File, + unsigned Line, + unsigned Col) { + return wrap(Builder->createLexicalBlock( + unwrapDI(Scope), + unwrapDI(File), Line, Col)); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable( + DIBuilderRef Builder, + unsigned Tag, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNo, + LLVMValueRef Ty, + bool AlwaysPreserve, + unsigned Flags, + unsigned ArgNo) { + return wrap(Builder->createLocalVariable(Tag, + unwrapDI(Scope), Name, + unwrapDI(File), + LineNo, + unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateArrayType( + DIBuilderRef Builder, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, + LLVMValueRef Subscripts) { + return wrap(Builder->createArrayType(Size, AlignInBits, + unwrapDI(Ty), + unwrapDI(Subscripts))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType( + DIBuilderRef Builder, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, + LLVMValueRef Subscripts) { + return wrap(Builder->createVectorType(Size, AlignInBits, + unwrapDI(Ty), + unwrapDI(Subscripts))); +} + +extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange( + DIBuilderRef Builder, + int64_t Lo, + int64_t Count) { + return wrap(Builder->getOrCreateSubrange(Lo, Count)); +} + +extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray( + DIBuilderRef Builder, + LLVMValueRef* Ptr, + unsigned Count) { + return wrap(Builder->getOrCreateArray( + ArrayRef(reinterpret_cast(Ptr), Count))); +} + +extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( + DIBuilderRef Builder, + LLVMValueRef Val, + LLVMValueRef VarInfo, + LLVMBasicBlockRef InsertAtEnd) { + return wrap(Builder->insertDeclare( + unwrap(Val), + unwrapDI(VarInfo), + unwrap(InsertAtEnd))); +} + +extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( + DIBuilderRef Builder, + LLVMValueRef Val, + LLVMValueRef VarInfo, + LLVMValueRef InsertBefore) { + return wrap(Builder->insertDeclare( + unwrap(Val), + unwrapDI(VarInfo), + unwrap(InsertBefore))); +} diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index f5397165781..2a3f7de9bf5 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -588,3 +588,22 @@ LLVMInlineAsm LLVMInitializePasses LLVMAddPass LLVMCreatePass +LLVMDIBuilderCreate +LLVMDIBuilderDispose +LLVMDIBuilderFinalize +LLVMDIBuilderCreateCompileUnit +LLVMDIBuilderCreateLocalVariable +LLVMDIBuilderCreateFunction +LLVMDIBuilderCreateFile +LLVMDIBuilderCreateLexicalBlock +LLVMDIBuilderCreateBasicType +LLVMDIBuilderCreatePointerType +LLVMDIBuilderCreateMemberType +LLVMDIBuilderCreateStructType +LLVMDIBuilderGetOrCreateSubrange +LLVMDIBuilderCreateArrayType +LLVMDIBuilderCreateVectorType +LLVMDIBuilderCreateSubroutineType +LLVMDIBuilderGetOrCreateArray +LLVMDIBuilderInsertDeclareAtEnd +LLVMDIBuilderInsertDeclareBefore diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 6f11202800c..d4202abd285 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -43,6 +43,8 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Vectorize.h" +#include "llvm/DebugInfo.h" +#include "llvm/DIBuilder.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/ExecutionEngine.h" diff --git a/src/test/debug-info/basic-types.rs b/src/test/debug-info/basic-types.rs index 20da6b557f1..616740c850c 100644 --- a/src/test/debug-info/basic-types.rs +++ b/src/test/debug-info/basic-types.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 // Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values) // as its numerical value along with its associated ASCII char, there @@ -17,8 +17,9 @@ // its numerical value. // compile-flags:-Z extra-debug-info -// debugger:break 67 +// debugger:break _zzz // debugger:run +// debugger:finish // debugger:print b // check:$1 = false // debugger:print i @@ -66,5 +67,7 @@ fn main() { let f: float = 1.5; let f32: f32 = 2.5; let f64: f64 = 3.5; - let _z = (); + _zzz(); } + +fn _zzz() {()} diff --git a/src/test/debug-info/box.rs b/src/test/debug-info/box.rs index 54aa0c12578..3e5483ad75b 100644 --- a/src/test/debug-info/box.rs +++ b/src/test/debug-info/box.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 // compile-flags:-Z extra-debug-info // debugger:set print pretty off -// debugger:break 29 +// debugger:break _zzz // debugger:run +// debugger:finish // debugger:print a->boxed // check:$1 = 1 // debugger:print b->boxed @@ -28,5 +29,7 @@ fn main() { let b = ~(2, 3.5); let c = @4; let d = @false; - let _z = 0; + _zzz(); } + +fn _zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct.rs b/src/test/debug-info/struct.rs index 16ba6cda590..ddfac9cbeea 100644 --- a/src/test/debug-info/struct.rs +++ b/src/test/debug-info/struct.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 // compile-flags:-Z extra-debug-info // debugger:set print pretty off -// debugger:break 29 +// debugger:break _zzz // debugger:run +// debugger:finish // debugger:print pair // check:$1 = {x = 1, y = 2} // debugger:print pair.x @@ -28,5 +29,7 @@ struct Pair { fn main() { let pair = Pair { x: 1, y: 2 }; - let _z = (); + _zzz(); } + +fn _zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/tuple.rs b/src/test/debug-info/tuple.rs index 35e2977f562..a50996871ce 100644 --- a/src/test/debug-info/tuple.rs +++ b/src/test/debug-info/tuple.rs @@ -8,16 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 // compile-flags:-Z extra-debug-info // debugger:set print pretty off -// debugger:break 20 +// debugger:break _zzz // debugger:run +// debugger:finish // debugger:print t // check:$1 = {4, 5.5, true} fn main() { let t = (4, 5.5, true); - let _z = (); + _zzz(); } + +fn _zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/vec.rs b/src/test/debug-info/vec.rs index 3876f1c46d4..c87849ac4b6 100644 --- a/src/test/debug-info/vec.rs +++ b/src/test/debug-info/vec.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 // compile-flags:-Z extra-debug-info // debugger:set print pretty off -// debugger:break 29 +// debugger:break _zzz // debugger:run +// debugger:finish // debugger:print a // check:$1 = {1, 2, 3} // debugger:print b.vec[0] @@ -28,5 +29,7 @@ fn main() { let b = &[4, 5, 6]; let c = @[7, 8, 9]; let d = ~[10, 11, 12]; - let _z = 0; + _zzz(); } + +fn _zzz() {()} \ No newline at end of file