diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index aeb2017c9d647..7acd9545efdd0 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1635,6 +1635,14 @@ pub mod llvm { #[fast_ffi] pub unsafe fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint; + + /** Computes the byte offset of the indexed struct element for a target. */ + #[fast_ffi] + pub unsafe fn LLVMOffsetOfElement(TD: TargetDataRef, + StructTy: TypeRef, + Element: c_uint) + -> c_ulonglong; + /** * Returns the minimum alignment of a type when part of a call frame. */ @@ -2089,6 +2097,37 @@ pub mod llvm { Val: ValueRef, VarInfo: DIVariable, InsertBefore: ValueRef) -> ValueRef; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateEnumerator( + Builder: DIBuilderRef, + Name: *c_char, + Val: c_ulonglong) -> ValueRef; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateEnumerationType( + Builder: DIBuilderRef, + Scope: ValueRef, + Name: *c_char, + File: ValueRef, + LineNumber: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Elements: ValueRef, + ClassType: ValueRef) -> ValueRef; + + #[fast_ffi] + pub unsafe fn LLVMDIBuilderCreateUnionType( + Builder: DIBuilderRef, + Scope: ValueRef, + Name: *c_char, + File: ValueRef, + LineNumber: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Flags: c_uint , + Elements: ValueRef, + RunTimeLang: c_uint) -> ValueRef; } } diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f336b0f4e4c5e..2934751eeafd7 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -90,7 +90,7 @@ pub fn maybe_get_item_ast(tcx: ty::ctxt, def: ast::def_id, } pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id) - -> ~[ty::VariantInfo] { + -> ~[@ty::VariantInfo] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index caa170605dec3..cf75bf45eaf0c 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -733,11 +733,11 @@ pub fn maybe_get_item_ast(cdata: cmd, tcx: ty::ctxt, } pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id, - tcx: ty::ctxt) -> ~[ty::VariantInfo] { + tcx: ty::ctxt) -> ~[@ty::VariantInfo] { let data = cdata.data; let items = reader::get_doc(reader::Doc(data), tag_items); let item = find_item(id, items); - let mut infos: ~[ty::VariantInfo] = ~[]; + let mut infos: ~[@ty::VariantInfo] = ~[]; let variant_ids = enum_variant_ids(item, cdata); let mut disr_val = 0; for variant_ids.iter().advance |did| { @@ -753,11 +753,16 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id, Some(val) => { disr_val = val; } _ => { /* empty */ } } - infos.push(@ty::VariantInfo_{args: arg_tys, - ctor_ty: ctor_ty, name: name, - // I'm not even sure if we encode visibility - // for variants -- TEST -- tjc - id: *did, disr_val: disr_val, vis: ast::inherited}); + infos.push(@ty::VariantInfo{ + args: arg_tys, + arg_names: None, + ctor_ty: ctor_ty, + name: name, + // I'm not even sure if we encode visibility + // for variants -- TEST -- tjc + id: *did, + disr_val: disr_val, + vis: ast::inherited}); disr_val += 1; } return infos; diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 821242d64c96c..fd38ec39bb1bb 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -94,7 +94,7 @@ pub enum Repr { } /// For structs, and struct-like parts of anything fancier. -struct Struct { +pub struct Struct { size: u64, align: u64, packed: bool, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 588b0b5c75f48..f6b5cffae7cd4 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -671,7 +671,7 @@ pub fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t, let _icx = push_ctxt("iter_structural_ty"); fn iter_variant(cx: block, repr: &adt::Repr, av: ValueRef, - variant: ty::VariantInfo, + variant: @ty::VariantInfo, tps: &[ty::t], f: val_and_ty_fn) -> block { let _icx = push_ctxt("iter_variant"); let tcx = cx.tcx(); @@ -1142,7 +1142,7 @@ pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { bcx = init_local(bcx, *local); if cx.sess().opts.extra_debuginfo && fcx_has_nonzero_span(bcx.fcx) { - debuginfo::create_local_var(bcx, *local); + debuginfo::create_local_var_metadata(bcx, *local); } } ast::decl_item(i) => trans_item(cx.fcx.ccx, i) @@ -1774,7 +1774,7 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt, bcx = _match::store_arg(bcx, args[arg_n].pat, llarg); if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) { - debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span); + debuginfo::create_argument_metadata(bcx, &args[arg_n], args[arg_n].ty.span); } } @@ -1948,7 +1948,7 @@ pub fn trans_fn(ccx: @mut CrateContext, |fcx| { if ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) { - debuginfo::create_function(fcx); + debuginfo::create_function_metadata(fcx); } }, |_bcx| { }); @@ -2110,7 +2110,7 @@ pub fn trans_enum_variant_or_tuple_like_struct( } pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def, - id: ast::node_id, vi: @~[ty::VariantInfo], + id: ast::node_id, vi: @~[@ty::VariantInfo], i: &mut uint) { for enum_definition.variants.iter().advance |variant| { let disr_val = vi[*i].disr_val; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 00b59d187bfd6..0e75e4e85c2f2 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -27,11 +27,18 @@ where possible. This will hopefully ease the adaption of this module to future L The public API of the module is a set of functions that will insert the correct metadata into the LLVM IR when called with the right parameters. The module is thus driven from an outside client with -functions like `debuginfo::create_local_var(bcx: block, local: @ast::local)`. +functions like `debuginfo::local_var_metadata(bcx: block, local: &ast::local)`. -Internally the module will try to reuse already created metadata by utilizing a cache. All private -state used by the module is stored within a DebugContext struct, which in turn is contained in the -CrateContext. +Internally the module will try to reuse already created metadata by utilizing a cache. The way to +get a shared metadata node when needed is thus to just call the corresponding function in this +module: + + let file_metadata = file_metadata(crate_context, path); + +The function will take care of probing the cache for an existing node for that exact file path. + +All private state used by the module is stored within a DebugContext struct, which in turn is +contained in the CrateContext. This file consists of three conceptual sections: @@ -44,31 +51,29 @@ This file consists of three conceptual sections: use driver::session; use lib::llvm::llvm; -use lib::llvm::{ValueRef, ModuleRef, ContextRef}; +use lib::llvm::{ModuleRef, ContextRef}; use lib::llvm::debuginfo::*; use middle::trans::common::*; use middle::trans::machine; use middle::trans::type_of; +use middle::trans::type_::Type; +use middle::trans::adt; use middle::trans; use middle::ty; use util::ppaux::ty_to_str; use std::hashmap::HashMap; -use std::libc; -use std::libc::{c_uint, c_ulonglong}; -use std::cmp; +use std::libc::{c_uint, c_ulonglong, c_longlong}; use std::ptr; use std::str::as_c_str; -use std::sys; use std::vec; use syntax::codemap::span; use syntax::{ast, codemap, ast_util, ast_map}; -use syntax::parse::token; static DW_LANG_RUST: int = 0x9000; -static AutoVariableTag: int = 256; -static ArgVariableTag: int = 257; +static DW_TAG_auto_variable: int = 0x100; +static DW_TAG_arg_variable: int = 0x101; static DW_ATE_boolean: int = 0x02; static DW_ATE_float: int = 0x04; @@ -118,7 +123,7 @@ impl DebugContext { /// Create any deferred debug metadata nodes pub fn finalize(cx: @mut CrateContext) { debug!("finalize"); - create_compile_unit(cx); + compile_unit_metadata(cx); unsafe { llvm::LLVMDIBuilderFinalize(DIB(cx)); llvm::LLVMDIBuilderDispose(DIB(cx)); @@ -129,7 +134,7 @@ pub fn finalize(cx: @mut CrateContext) { /// /// Adds the created metadata nodes directly to the crate's IR. /// The return value should be ignored if called from outside of the debuginfo module. -pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { +pub fn create_local_var_metadata(bcx: block, local: @ast::local) -> DIVariable { let cx = bcx.ccx(); let ident = match local.node.pat.node { @@ -140,24 +145,35 @@ pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { return ptr::null(); } }; + let name: &str = cx.sess.str_of(ident); - debug!("create_local_var: %s", name); + debug!("create_local_var_metadata: %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, loc.file.name); + let type_metadata = type_metadata(cx, ty, local.node.ty.span); + let file_metadata = file_metadata(cx, loc.file.name); + let context = match bcx.parent { - None => create_function(bcx.fcx), - Some(_) => create_block(bcx) + None => create_function_metadata(bcx.fcx), + Some(_) => lexical_block_metadata(bcx) }; - 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) - }}; + let var_metadata = do as_c_str(name) |name| { + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + DW_TAG_auto_variable as u32, + context, + name, + file_metadata, + loc.line as c_uint, + type_metadata, + 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) { @@ -169,24 +185,25 @@ pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { } }; - set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); + set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint()); unsafe { - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_md, bcx.llbb); + let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_metadata, bcx.llbb); llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); } - return var_md; + return var_metadata; } /// Creates debug information for the given function argument. /// /// Adds the created metadata nodes directly to the crate's IR. /// The return value should be ignored if called from outside of the debuginfo module. -pub fn create_arg(bcx: block, arg: &ast::arg, span: span) -> Option { - debug!("create_arg"); +pub fn create_argument_metadata(bcx: block, arg: &ast::arg, span: span) -> Option { + debug!("create_argument_metadata"); 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)`" + // XXX create_argument_metadata 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; } @@ -199,38 +216,40 @@ pub fn create_arg(bcx: block, arg: &ast::arg, span: span) -> Option } let ty = node_id_type(bcx, arg.id); - let tymd = create_ty(cx, ty, arg.ty.span); - let filemd = create_file(cx, loc.file.name); - let context = create_function(fcx); + let type_metadata = type_metadata(cx, ty, arg.ty.span); + let file_metadata = file_metadata(cx, loc.file.name); + let context = create_function_metadata(fcx); match arg.pat.node { ast::pat_ident(_, ref path, _) => { // XXX: This is wrong; it should work for multiple bindings. 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) + let var_metadata = do as_c_str(name) |name| { + unsafe { + llvm::LLVMDIBuilderCreateLocalVariable( + DIB(cx), + DW_TAG_arg_variable as u32, + context, + name, + file_metadata, + loc.line as c_uint, + type_metadata, + false, + 0, + 0) // XXX need to pass in a real argument number - }}; + } + }; let llptr = fcx.llargs.get_copy(&arg.id); - set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint()); + set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint()); unsafe { let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( - DIB(cx), llptr, mdnode, bcx.llbb); + DIB(cx), llptr, var_metadata, bcx.llbb); llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr); } - return Some(mdnode); + return Some(var_metadata); } _ => { return None; @@ -247,59 +266,81 @@ pub fn update_source_pos(bcx: block, span: span) { } 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()) + set_debug_location(bcx.ccx(), lexical_block_metadata(bcx), loc.line, loc.col.to_uint()) } /// Creates debug information for the given function. /// /// Adds the created metadata nodes directly to the crate's IR. /// The return value should be ignored if called from outside of the debuginfo module. -pub fn create_function(fcx: fn_ctxt) -> DISubprogram { +pub fn create_function_metadata(fcx: fn_ctxt) -> DISubprogram { let cx = fcx.ccx; let fcx = &mut *fcx; let span = fcx.span.get(); let fnitem = cx.tcx.items.get_copy(&fcx.id); let (ident, ret_ty, id) = match fnitem { - ast_map::node_item(ref item, _) => { - match item.node { - ast::item_fn(ast::fn_decl { output: ref ty, _}, _, _, _, _) => { - (item.ident, ty, item.id) - } - _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function") + ast_map::node_item(ref item, _) => { + match item.node { + ast::item_fn(ast::fn_decl { output: ref ty, _}, _, _, _, _) => { + (item.ident, ty, item.id) + } + _ => fcx.ccx.sess.span_bug(item.span, + "create_function_metadata: item bound to non-function") + } } - } - ast_map::node_method(@ast::method { decl: ast::fn_decl { output: ref ty, _ }, - id: id, ident: ident, _}, _, _) => { - (ident, ty, id) - } - ast_map::node_expr(ref expr) => { - match expr.node { - ast::expr_fn_block(ref decl, _) => { - let name = gensym_name("fn"); - (name, &decl.output, expr.id) - } - _ => fcx.ccx.sess.span_bug(expr.span, - "create_function: expected an expr_fn_block here") + ast_map::node_method( + @ast::method { + decl: ast::fn_decl { output: ref ty, _ }, + id: id, + ident: ident, + _ + }, + _, + _) => { + (ident, ty, id) } - } - _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") + ast_map::node_expr(ref expr) => { + match expr.node { + ast::expr_fn_block(ref decl, _) => { + let name = gensym_name("fn"); + (name, &decl.output, expr.id) + } + _ => fcx.ccx.sess.span_bug(expr.span, + "create_function_metadata: expected an expr_fn_block here") + } + } + ast_map::node_trait_method( + @ast::provided( + @ast::method { + decl: ast::fn_decl { output: ref ty, _ }, + id: id, + ident: ident, + _ + }), + _, + _) => { + (ident, ty, id) + } + _ => fcx.ccx.sess.bug("create_function_metadata: unexpected sort of node") }; match dbg_cx(cx).created_functions.find(&id) { - Some(fn_md) => return *fn_md, + Some(fn_metadata) => return *fn_metadata, None => () } - debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span)); + debug!("create_function_metadata: %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 file_metadata = file_metadata(cx, loc.file.name); - let ret_ty_md = if cx.sess.opts.extra_debuginfo { + let return_type_metadata = if cx.sess.opts.extra_debuginfo { match ret_ty.node { ast::ty_nil => ptr::null(), - _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span) + _ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span) } } else { ptr::null() @@ -308,33 +349,35 @@ pub fn create_function(fcx: fn_ctxt) -> DISubprogram { let fn_ty = unsafe { llvm::LLVMDIBuilderCreateSubroutineType( DIB(cx), - file_md, - create_DIArray(DIB(cx), [ret_ty_md])) + file_metadata, + create_DIArray(DIB(cx), [return_type_metadata])) }; - let fn_md = + let fn_metadata = 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()) - }}}; + do as_c_str(cx.sess.str_of(ident)) |linkage| { + unsafe { + llvm::LLVMDIBuilderCreateFunction( + DIB(cx), + file_metadata, + name, + linkage, + file_metadata, + 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; + dbg_cx(cx).created_functions.insert(id, fn_metadata); + return fn_metadata; } @@ -350,11 +393,11 @@ fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { }; } -fn create_compile_unit(cx: @mut CrateContext) { +fn compile_unit_metadata(cx: @mut CrateContext) { let dcx = dbg_cx(cx); let crate_name: &str = dcx.crate_file; - debug!("create_compile_unit: %?", crate_name); + debug!("compile_unit_metadata: %?", crate_name); let work_dir = cx.sess.working_dir.to_str(); let producer = fmt!("rustc version %s", env!("CFG_VERSION")); @@ -363,21 +406,23 @@ fn create_compile_unit(cx: @mut CrateContext) { 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); - }}}}}}; + 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) -> DIFile { +fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile { match dbg_cx(cx).created_files.find_equiv(&full_path) { - Some(file_md) => return *file_md, + Some(file_metadata) => return *file_metadata, None => () } - debug!("create_file: %s", full_path); + debug!("file_metadata: %s", full_path); let work_dir = cx.sess.working_dir.to_str(); let file_name = @@ -387,68 +432,67 @@ fn create_file(cx: &mut CrateContext, full_path: &str) -> DIFile { full_path }; - let file_md = + let file_metadata = 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) - }}}; + 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; + dbg_cx(cx).created_files.insert(full_path.to_owned(), file_metadata); + return file_metadata; } - - -fn create_block(bcx: block) -> DILexicalBlock { - let mut bcx = bcx; +/// Get or create the lexical block metadata node for the given LLVM basic block. +fn lexical_block_metadata(bcx: block) -> DILexicalBlock { let cx = bcx.ccx(); + let mut bcx = bcx; + // Search up the tree of basic blocks until we find one that knows the containing lexical block. while bcx.node_info.is_none() { match bcx.parent { - Some(b) => bcx = b, - None => fail!() + Some(b) => bcx = b, + None => cx.sess.bug("debuginfo: Could not find lexical block for LLVM basic block.") } } + let span = bcx.node_info.get().span; let id = bcx.node_info.get().id; + // Check whether we already have a cache entry for this node id match dbg_cx(cx).created_blocks.find(&id) { Some(block) => return *block, None => () } - debug!("create_block: %s", bcx.sess().codemap.span_to_str(span)); + debug!("lexical_block_metadata: %s", bcx.sess().codemap.span_to_str(span)); let parent = match bcx.parent { - None => create_function(bcx.fcx), - Some(b) => create_block(b) + None => create_function_metadata(bcx.fcx), + Some(b) => lexical_block_metadata(b) }; - let cx = bcx.ccx(); + let loc = span_start(cx, span); - let file_md = create_file(cx, loc.file.name); + let file_metadata = file_metadata(cx, loc.file.name); - let block_md = unsafe { + let lexical_block_metadata = unsafe { llvm::LLVMDIBuilderCreateLexicalBlock( DIB(cx), - parent, file_md, - loc.line as c_uint, loc.col.to_uint() as c_uint) + parent, + file_metadata, + loc.line as c_uint, + loc.col.to_uint() as c_uint) }; - dbg_cx(cx).created_blocks.insert(id, block_md); + dbg_cx(cx).created_blocks.insert(id, lexical_block_metadata); - return block_md; + return lexical_block_metadata; } +fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType { - -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)); + debug!("basic_type_metadata: %?", ty::get(t)); let (name, encoding) = match ty::get(t).sty { ty::ty_nil | ty::ty_bot => (~"uint", DW_ATE_unsigned), @@ -473,424 +517,805 @@ fn create_basic_type(cx: &mut CrateContext, t: ty::t, _span: span) -> DIType { 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::basic_type_metadata - t is invalid type") }; - let (size, align) = size_and_align_of(cx, t); - let ty_md = do as_c_str(name) |name| { unsafe { + let llvm_type = type_of::type_of(cx, t); + let (size, align) = size_and_align_of(cx, llvm_type); + let ty_metadata = do as_c_str(name) |name| { + unsafe { llvm::LLVMDIBuilderCreateBasicType( DIB(cx), name, bytes_to_bits(size), bytes_to_bits(align), encoding as c_uint) - }}; + } + }; - // One could think that this call is not necessary, as the create_ty() function will insert the - // type descriptor into the cache anyway. Mind, however, that create_basic_type() is also called - // directly from other functions (e.g. create_boxed_type()). - dbg_cx(cx).created_types.insert(ty_id, ty_md); - return ty_md; + return ty_metadata; } -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 name = ty_to_str(cx.tcx, t); - let ptr_md = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreatePointerType( - DIB(cx), - pointee, - bytes_to_bits(size), - bytes_to_bits(align), - name) - }}; - return ptr_md; +fn pointer_type_metadata(cx: &mut CrateContext, + pointer_type: ty::t, + pointee_type_metadata: DIType) + -> DIType { + let pointer_llvm_type = type_of::type_of(cx, pointer_type); + let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type); + let name = ty_to_str(cx.tcx, pointer_type); + let ptr_metadata = do as_c_str(name) |name| { + unsafe { + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + bytes_to_bits(pointer_size), + bytes_to_bits(pointer_align), + name) + } + }; + return ptr_metadata; } -struct StructContext { - builder: DIBuilderRef, - file: DIFile, - name: ~str, - line: uint, - members: ~[DIDerivedType], - total_size: uint, - align: uint -} - -impl StructContext { - fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> StructContext { - debug!("StructContext::create: %s", name); - return StructContext { - builder: DIB(cx), - file: file, - name: name, - line: line, - members: ~[], - total_size: 0, - align: 1 - }; +fn struct_metadata(cx: &mut CrateContext, + struct_type: ty::t, + fields: ~[ty::field], + span: span) + -> DICompositeType { + let struct_name = ty_to_str(cx.tcx, struct_type); + debug!("struct_metadata: %s", struct_name); + + let struct_llvm_type = type_of::type_of(cx, struct_type); + + let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) }; + let field_names = do fields.map |field| { cx.sess.str_of(field.ident).to_owned() }; + let field_types_metadata = do fields.map |field| { + type_metadata(cx, field.mt.ty, span) + }; + + return composite_type_metadata( + cx, + struct_llvm_type, + struct_name, + field_llvm_types, + field_names, + field_types_metadata, + span); +} + +fn tuple_metadata(cx: &mut CrateContext, + tuple_type: ty::t, + component_types: &[ty::t], + span: span) + -> DICompositeType { + + let tuple_name = ty_to_str(cx.tcx, tuple_type); + let tuple_llvm_type = type_of::type_of(cx, tuple_type); + + let component_names = do component_types.map |_| { ~"" }; + let component_llvm_types = do component_types.map |it| { type_of::type_of(cx, *it) }; + let component_types_metadata = do component_types.map |it| { + type_metadata(cx, *it, span) + }; + + return composite_type_metadata( + cx, + tuple_llvm_type, + tuple_name, + component_llvm_types, + component_names, + component_types_metadata, + span); +} + +// The stage0 snapshot does not yet support the fixes from PR #7557, so there are two versions of +// following function for now +#[cfg(not(stage0))] +fn enum_metadata(cx: &mut CrateContext, + enum_type: ty::t, + enum_def_id: ast::def_id, + // _substs is only needed in the other version. Will go away with new snapshot. + _substs: &ty::substs, + span: span) + -> DIType { + + let enum_name = ty_to_str(cx.tcx, enum_type); + + // For empty enums there is an early exit. Just describe it as an empty struct with the + // appropriate type name + if ty::type_is_empty(cx.tcx, enum_type) { + return composite_type_metadata(cx, Type::nil(), enum_name, [], [], [], span); } - fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) { - let offset = roundup(self.total_size, align); + // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be + // needed in all of the following cases. + let discriminant_llvm_type = Type::enum_discrim(cx); + let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type); - debug!("StructContext(%s)::add_member: %s, size=%u, align=%u, offset=%u", - self.name, name, size, align, offset); + assert!(Type::enum_discrim(cx) == cx.int_type); + let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span); - let mem_t = do as_c_str(name) |name| { unsafe { - llvm::LLVMDIBuilderCreateMemberType( - self.builder, - self.file, - name, - self.file, - line as c_uint, - bytes_to_bits(size), - bytes_to_bits(align), - bytes_to_bits(offset), - 0, - ty) + let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id); + + let enumerators_metadata: ~[DIDescriptor] = variants + .iter() + .transform(|v| { + let name: &str = cx.sess.str_of(v.name); + let discriminant_value = v.disr_val as c_ulonglong; + + do name.as_c_str |name| { + unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name, + discriminant_value) + } + } + }) + .collect(); + + let loc = span_start(cx, span); + let file_metadata = file_metadata(cx, loc.file.name); + + let discriminant_type_metadata = do enum_name.as_c_str |enum_name| { + unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + file_metadata, + enum_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_metadata), + discriminant_type_metadata) + } + }; + + let type_rep = adt::represent_type(cx, enum_type); + + match *type_rep { + adt::CEnum(*) => { + return discriminant_type_metadata; + } + adt::Univariant(ref struct_def, _) => { + assert!(variants.len() == 1); + return adt_struct_metadata(cx, struct_def, variants[0], None, span); + } + adt::General(ref struct_defs) => { + let variants_member_metadata: ~[DIDescriptor] = do struct_defs + .iter() + .enumerate() + .transform |(i, struct_def)| { + let variant_type_metadata = adt_struct_metadata( + cx, + struct_def, + variants[i], + Some(discriminant_type_metadata), + span); + + do "".as_c_str |name| { + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + file_metadata, + name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(struct_def.size as uint), + bytes_to_bits(struct_def.align as uint), + bytes_to_bits(0), + 0, + variant_type_metadata) + } + } + }.collect(); + + let enum_llvm_type = type_of::type_of(cx, enum_type); + let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type); + + return do enum_name.as_c_str |enum_name| { + unsafe { + llvm::LLVMDIBuilderCreateUnionType( + DIB(cx), + file_metadata, + enum_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + create_DIArray(DIB(cx), variants_member_metadata), + 0) // RuntimeLang }}; - 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); + } + adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => { + return adt_struct_metadata(cx, struct_def, variants[nndiscr], None, span); + } } - fn get_total_size_with_alignment(&self) -> uint { - roundup(self.total_size, self.align) - } + fn adt_struct_metadata(cx: &mut CrateContext, + struct_def: &adt::Struct, + variant_info: &ty::VariantInfo, + discriminant_type_metadata: Option, + span: span) + -> DICompositeType + { + let arg_llvm_types: ~[Type] = do struct_def.fields.map |&ty| { type_of::type_of(cx, ty) }; + let arg_metadata: ~[DIType] = do struct_def.fields.iter().enumerate() + .transform |(i, &ty)| { + match discriminant_type_metadata { + Some(metadata) if i == 0 => metadata, + _ => type_metadata(cx, ty, span) + } + }.collect(); - 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); - - // The size of the struct/tuple must be rounded to the next multiple of its alignment. - // Otherwise gdb has trouble reading the struct correctly when it is embedded into another - // data structure. This is also the value `sizeof` in C would give. - let actual_total_size = self.get_total_size_with_alignment(); - - 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, - bytes_to_bits(actual_total_size), - bytes_to_bits(self.align), - 0, - ptr::null(), - members_md, - 0, - ptr::null()) - }}; - return struct_md; + let mut arg_names = match variant_info.arg_names { + Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() }, + None => do variant_info.args.map |_| { ~"" } + }; + + if discriminant_type_metadata.is_some() { + arg_names.insert(0, ~""); + } + + let variant_llvm_type = Type::struct_(arg_llvm_types, struct_def.packed); + let variant_name: &str = cx.sess.str_of(variant_info.name); + + return composite_type_metadata( + cx, + variant_llvm_type, + variant_name, + arg_llvm_types, + arg_names, + arg_metadata, + span); } } -fn create_struct(cx: &mut CrateContext, struct_type: ty::t, fields: ~[ty::field], span: span) - -> DICompositeType { - debug!("create_struct: %?", ty::get(struct_type)); +#[cfg(stage0)] +fn enum_metadata(cx: &mut CrateContext, + enum_type: ty::t, + enum_def_id: ast::def_id, + substs: &ty::substs, + span: span) + -> DIType { + + let enum_name = ty_to_str(cx.tcx, enum_type); + + // For empty enums there is an early exit. Just describe it as an empty struct with the + // appropriate type name + if ty::type_is_empty(cx.tcx, enum_type) { + return composite_type_metadata(cx, Type::nil(), enum_name, &[], &[], &[], span); + } + + // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be + // needed in all of the following cases. + let discriminant_llvm_type = Type::enum_discrim(cx); + let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type); + + assert!(Type::enum_discrim(cx) == cx.int_type); + let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span); + + let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id); + + let enumerators_metadata: ~[DIDescriptor] = variants + .iter() + .transform(|v| { + let name: &str = cx.sess.str_of(v.name); + let discriminant_value = v.disr_val as c_ulonglong; + + do name.as_c_str |name| { + unsafe { + llvm::LLVMDIBuilderCreateEnumerator( + DIB(cx), + name, + discriminant_value) + } + } + }) + .collect(); let loc = span_start(cx, span); - let file_md = create_file(cx, loc.file.name); - - let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, struct_type), file_md, loc.line); - for fields.iter().advance |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); - scx.add_member(cx.sess.str_of(field.ident), loc.line, size, align, ty_md); + let file_metadata = file_metadata(cx, loc.file.name); + + let discriminant_type_metadata = do enum_name.as_c_str |enum_name| { + unsafe { + llvm::LLVMDIBuilderCreateEnumerationType( + DIB(cx), + file_metadata, + enum_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(discriminant_size), + bytes_to_bits(discriminant_align), + create_DIArray(DIB(cx), enumerators_metadata), + discriminant_type_metadata) + } + }; + + if ty::type_is_c_like_enum(cx.tcx, enum_type) { + return discriminant_type_metadata; } - return scx.finalize(); -} -// returns (void* type as a ValueRef, size in bytes, align in bytes) -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( + let is_univariant = variants.len() == 1; + + let variants_metadata = do variants.map |&vi| { + + let raw_types: &[ty::t] = vi.args; + let arg_types = do raw_types.map |&raw_type| { ty::subst(cx.tcx, substs, raw_type) }; + + let mut arg_llvm_types = do arg_types.map |&ty| { type_of::type_of(cx, ty) }; + let mut arg_names = match vi.arg_names { + Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() }, + None => do arg_types.map |_| { ~"" } + }; + + let mut arg_metadata = do arg_types.map |&ty| { type_metadata(cx, ty, span) }; + + if !is_univariant { + arg_llvm_types.insert(0, discriminant_llvm_type); + arg_names.insert(0, ~""); + arg_metadata.insert(0, discriminant_type_metadata); + } + + let variant_llvm_type = Type::struct_(arg_llvm_types, false); + let (variant_type_size, variant_type_align) = size_and_align_of(cx, variant_llvm_type); + + let variant_type_metadata = composite_type_metadata( + cx, + variant_llvm_type, + &"", + arg_llvm_types, + arg_names, + arg_metadata, + span); + + do "".as_c_str |name| { + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + file_metadata, + name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(variant_type_size), + bytes_to_bits(variant_type_align), + bytes_to_bits(0), + 0, + variant_type_metadata) + } + } + }; + + let enum_llvm_type = type_of::type_of(cx, enum_type); + let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type); + + return do enum_name.as_c_str |enum_name| { + unsafe { + llvm::LLVMDIBuilderCreateUnionType( DIB(cx), - ptr::null(), - bytes_to_bits(size), - bytes_to_bits(align), - name) - }}; - return (vp, size, align); + file_metadata, + enum_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(enum_type_size), + bytes_to_bits(enum_type_align), + 0, // Flags + create_DIArray(DIB(cx), variants_metadata), + 0) // RuntimeLang + } + }; } -fn create_tuple(cx: &mut CrateContext, tuple_type: ty::t, elements: &[ty::t], span: span) - -> DICompositeType { - debug!("create_tuple: %?", ty::get(tuple_type)); + +/// Creates debug information for a composite type, that is, anything that results in a LLVM struct. +/// +/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums. +fn composite_type_metadata(cx: &mut CrateContext, + composite_llvm_type: Type, + composite_type_name: &str, + member_llvm_types: &[Type], + member_names: &[~str], + member_type_metadata: &[DIType], + span: span) + -> DICompositeType { let loc = span_start(cx, span); - let file_md = create_file(cx, loc.file.name); - - let name = fmt!("tuple_%u", token::gensym("tuple")); - let mut scx = StructContext::new(cx, name, file_md, loc.line); - for elements.iter().advance |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); + let file_metadata = file_metadata(cx, loc.file.name); + + let (composite_size, composite_align) = size_and_align_of(cx, composite_llvm_type); + + let member_metadata: ~[DIDescriptor] = member_llvm_types + .iter() + .enumerate() + .transform(|(i, &member_llvm_type)| { + let (member_size, member_align) = size_and_align_of(cx, member_llvm_type); + let member_offset = machine::llelement_offset(cx, composite_llvm_type, i); + let member_name: &str = member_names[i]; + + do member_name.as_c_str |member_name| { + unsafe { + llvm::LLVMDIBuilderCreateMemberType( + DIB(cx), + file_metadata, + member_name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(member_size), + bytes_to_bits(member_align), + bytes_to_bits(member_offset), + 0, + member_type_metadata[i]) + } + } + }) + .collect(); + + return do composite_type_name.as_c_str |name| { + unsafe { + llvm::LLVMDIBuilderCreateStructType( + DIB(cx), + file_metadata, + name, + file_metadata, + loc.line as c_uint, + bytes_to_bits(composite_size), + bytes_to_bits(composite_align), + 0, + ptr::null(), + create_DIArray(DIB(cx), member_metadata), + 0, + ptr::null()) } - return scx.finalize(); + }; } -fn create_boxed_type(cx: &mut CrateContext, contents: ty::t, - span: span, boxed: DIType) -> DICompositeType { - debug!("create_boxed_type: %?", ty::get(contents)); +fn boxed_type_metadata(cx: &mut CrateContext, + content_type_name: Option<&str>, + content_llvm_type: Type, + content_type_metadata: DIType, + span: span) + -> 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 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(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); - scx.add_member("boxed", 0, size, align, boxed); - return scx.finalize(); -} - -fn create_fixed_vec(cx: &mut CrateContext, _vec_t: ty::t, elem_t: ty::t, - len: uint, span: span) -> DIType { - debug!("create_fixed_vec: %?", ty::get(_vec_t)); - - let elem_ty_md = create_ty(cx, elem_t, span); - let (size, align) = size_and_align_of(cx, elem_t); + let box_type_name = match content_type_name { + Some(content_type_name) => fmt!("Boxed<%s>", content_type_name), + None => ~"BoxedType" + }; + + let box_llvm_type = Type::box(cx, &content_llvm_type); + let member_llvm_types = box_llvm_type.field_types(); + let member_names = [~"refcnt", ~"tydesc", ~"prev", ~"next", ~"val"]; + + assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type)); + + let int_type = ty::mk_int(); + let nil_pointer_type = ty::mk_nil_ptr(cx.tcx); + + let member_types_metadata = [ + type_metadata(cx, int_type, span), + type_metadata(cx, nil_pointer_type, span), + type_metadata(cx, nil_pointer_type, span), + type_metadata(cx, nil_pointer_type, span), + content_type_metadata + ]; + + return composite_type_metadata( + cx, + box_llvm_type, + box_type_name, + member_llvm_types, + member_names, + member_types_metadata, + span); + + // Unfortunately, we cannot assert anything but the correct types here---and not whether the + // 'next' and 'prev' pointers are in the correct order. + fn box_layout_is_correct(cx: &CrateContext, + member_llvm_types: &[Type], + content_llvm_type: Type) + -> bool { + member_llvm_types.len() == 5 && + member_llvm_types[0] == cx.int_type && + member_llvm_types[1] == cx.tydesc_type.ptr_to() && + member_llvm_types[2] == Type::i8().ptr_to() && + member_llvm_types[3] == Type::i8().ptr_to() && + member_llvm_types[4] == content_llvm_type + } +} + +fn fixed_vec_metadata(cx: &mut CrateContext, + element_type: ty::t, + len: uint, + span: span) + -> DIType { + let element_type_metadata = type_metadata(cx, element_type, span); + let element_llvm_type = type_of::type_of(cx, element_type); + let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type); let subrange = unsafe { - llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, len as i64) + llvm::LLVMDIBuilderGetOrCreateSubrange( + DIB(cx), + 0, + len as c_longlong) }; let subscripts = create_DIArray(DIB(cx), [subrange]); return unsafe { llvm::LLVMDIBuilderCreateArrayType( DIB(cx), - bytes_to_bits(size * len), - bytes_to_bits(align), - elem_ty_md, + bytes_to_bits(element_type_size * len), + bytes_to_bits(element_type_align), + element_type_metadata, subscripts) }; } -fn create_boxed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, - vec_ty_span: span) -> DICompositeType { - debug!("create_boxed_vec: %?", ty::get(vec_t)); - - 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); +fn vec_metadata(cx: &mut CrateContext, + element_type: ty::t, + span: span) + -> DICompositeType { - 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); + let element_type_metadata = type_metadata(cx, element_type, span); + let element_llvm_type = type_of::type_of(cx, element_type); + let (element_size, element_align) = size_and_align_of(cx, element_llvm_type); - 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 vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type); + let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_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 member_llvm_types = vec_llvm_type.field_types(); + let member_names = &[~"fill", ~"alloc", ~"elements"]; - let subscripts = create_DIArray(DIB(cx), [subrange]); - let data_ptr = unsafe { + let int_type_metadata = type_metadata(cx, ty::mk_int(), span); + let array_type_metadata = unsafe { llvm::LLVMDIBuilderCreateArrayType( DIB(cx), - bytes_to_bits(arr_size), - bytes_to_bits(arr_align), - elem_ty_md, - subscripts) + bytes_to_bits(element_size), + bytes_to_bits(element_align), + element_type_metadata, + create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)])) }; - 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(); + // fill alloc elements + let member_type_metadata = &[int_type_metadata, int_type_metadata, array_type_metadata]; + + return composite_type_metadata( + cx, + vec_llvm_type, + vec_type_name, + member_llvm_types, + member_names, + member_type_metadata, + span); +} - 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); +fn boxed_vec_metadata(cx: &mut CrateContext, + element_type: ty::t, + span: span) + -> DICompositeType { + + let element_llvm_type = type_of::type_of(cx, element_type); + let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type); + let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type)); + let vec_metadata = vec_metadata(cx, element_type, span); + + return boxed_type_metadata( + cx, + Some(vec_type_name), + vec_llvm_type, + vec_metadata, + span); +} - 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) - -> DICompositeType { - debug!("create_vec_slice: %?", ty::get(vec_t)); +fn vec_slice_metadata(cx: &mut CrateContext, + vec_type: ty::t, + element_type: 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); + debug!("vec_slice_metadata: %?", ty::get(vec_type)); + + let slice_llvm_type = type_of::type_of(cx, vec_type); + let slice_type_name = ty_to_str(cx.tcx, vec_type); + + let member_llvm_types = slice_llvm_type.field_types(); + let member_names = &[~"data_ptr", ~"size_in_bytes"]; - 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(); + assert!(slice_layout_is_correct(cx, member_llvm_types, element_type)); + + let data_ptr_type = ty::mk_ptr(cx.tcx, ty::mt { ty: element_type, mutbl: ast::m_imm }); + + let member_type_metadata = &[type_metadata(cx, data_ptr_type, span), + type_metadata(cx, ty::mk_uint(), span)]; + + return composite_type_metadata( + cx, + slice_llvm_type, + slice_type_name, + member_llvm_types, + member_names, + member_type_metadata, + span); + + fn slice_layout_is_correct(cx: &mut CrateContext, + member_llvm_types: &[Type], + element_type: ty::t) + -> bool { + member_llvm_types.len() == 2 && + member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() && + member_llvm_types[1] == cx.int_type + } } -fn create_fn_ty(cx: &mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, - span: span) -> DICompositeType { - debug!("create_fn_ty: %?", ty::get(_fn_ty)); +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)); 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) }; - let members = ~[output_ptr_md, vp] + inputs_vals; + 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 inputs_vals = do inputs.map |arg| { type_metadata(cx, *arg, span) }; + let members = ~[output_ptr_metadata, nil_pointer_type_metadata] + inputs_vals; return unsafe { llvm::LLVMDIBuilderCreateSubroutineType( DIB(cx), - file_md, + file_metadata, create_DIArray(DIB(cx), members)) }; } -fn create_unimpl_ty(cx: &mut CrateContext, t: ty::t) -> DIType { - debug!("create_unimpl_ty: %?", ty::get(t)); +fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType { + debug!("unimplemented_type_metadata: %?", ty::get(t)); 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; + let metadata = 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 metadata; } -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, +fn type_metadata(cx: &mut CrateContext, + t: ty::t, + span: span) + -> DIType { + let type_id = ty::type_id(t); + match dbg_cx(cx).created_types.find(&type_id) { + Some(type_metadata) => return *type_metadata, None => () } - debug!("create_ty: %?", ty::get(t)); + fn create_pointer_to_box_metadata(cx: &mut CrateContext, + pointer_type: ty::t, + type_in_box: ty::t) + -> DIType { + + let content_type_name: &str = ty_to_str(cx.tcx, type_in_box); + let content_llvm_type = type_of::type_of(cx, type_in_box); + let content_type_metadata = type_metadata( + cx, + type_in_box, + codemap::dummy_sp()); + + let box_metadata = boxed_type_metadata( + cx, + Some(content_type_name), + content_llvm_type, + content_type_metadata, + codemap::dummy_sp()); + + pointer_type_metadata(cx, pointer_type, box_metadata) + } + + debug!("type_metadata: %?", ty::get(t)); let sty = &ty::get(t).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), + let type_metadata = match *sty { + ty::ty_nil | + ty::ty_bot | + ty::ty_bool | + ty::ty_int(_) | + ty::ty_uint(_) | + ty::ty_float(_) => { + basic_type_metadata(cx, t) + }, 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 + 1, span) + fixed_vec_metadata(cx, i8_t, len + 1, span) }, - ty::vstore_uniq | ty::vstore_box => { - let box_md = create_boxed_vec(cx, t, i8_t, span); - create_pointer_type(cx, t, span, box_md) + ty::vstore_uniq => { + let vec_metadata = vec_metadata(cx, i8_t, span); + pointer_type_metadata(cx, t, vec_metadata) + } + ty::vstore_box => { + let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, span); + pointer_type_metadata(cx, t, boxed_vec_metadata) } ty::vstore_slice(_region) => { - create_vec_slice(cx, t, i8_t, span) + vec_slice_metadata(cx, t, i8_t, span) } } }, - ty::ty_enum(_did, ref _substs) => { - 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); - let box_md = create_boxed_type(cx, mt.ty, span, boxed); - create_pointer_type(cx, t, span, box_md) + ty::ty_enum(def_id, ref substs) => { + enum_metadata(cx, t, def_id, substs, span) + }, + ty::ty_box(ref mt) => { + create_pointer_to_box_metadata(cx, t, mt.ty) }, ty::ty_evec(ref mt, ref vstore) => { match *vstore { ty::vstore_fixed(len) => { - 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); - create_pointer_type(cx, t, span, box_md) - }, - ty::vstore_slice(_region) => { - create_vec_slice(cx, t, mt.ty, span) + fixed_vec_metadata(cx, mt.ty, len, span) + } + ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).contains_managed() => { + let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span); + pointer_type_metadata(cx, t, boxed_vec_metadata) + } + ty::vstore_uniq => { + let vec_metadata = vec_metadata(cx, mt.ty, span); + pointer_type_metadata(cx, t, vec_metadata) + } + ty::vstore_box => { + let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span); + pointer_type_metadata(cx, t, boxed_vec_metadata) + } + ty::vstore_slice(_) => { + vec_slice_metadata(cx, t, mt.ty, span) } } }, - ty::ty_ptr(ref mt) => { - let pointee = create_ty(cx, mt.ty, span); - create_pointer_type(cx, t, span, pointee) + ty::ty_uniq(ref mt) if ty::type_contents(cx.tcx, mt.ty).contains_managed() => { + create_pointer_to_box_metadata(cx, t, mt.ty) }, + ty::ty_uniq(ref mt) | + ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { - let pointee = create_ty(cx, mt.ty, span); - create_pointer_type(cx, t, span, pointee) + let pointee = type_metadata(cx, mt.ty, span); + 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; - create_fn_ty(cx, t, inputs, output, span) + bare_fn_metadata(cx, t, inputs, output, span) }, ty::ty_closure(ref _closurety) => { cx.sess.span_note(span, "debuginfo for closure NYI"); - create_unimpl_ty(cx, t) + unimplemented_type_metadata(cx, t) }, ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => { cx.sess.span_note(span, "debuginfo for trait NYI"); - create_unimpl_ty(cx, t) + unimplemented_type_metadata(cx, t) }, ty::ty_struct(did, ref substs) => { let fields = ty::struct_fields(cx.tcx, did, substs); - create_struct(cx, t, fields, span) + struct_metadata(cx, t, fields, span) }, ty::ty_tup(ref elements) => { - create_tuple(cx, t, *elements, span) + tuple_metadata(cx, t, *elements, span) }, - _ => cx.sess.bug("debuginfo: unexpected type in create_ty") + _ => cx.sess.bug("debuginfo: unexpected type in type_metadata") }; - dbg_cx(cx).created_types.insert(ty_id, ty_md); - return ty_md; + dbg_cx(cx).created_types.insert(type_id, type_metadata); + return type_metadata; } fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) { @@ -926,9 +1351,8 @@ fn span_start(cx: &CrateContext, span: span) -> codemap::Loc { cx.sess.codemap.lookup_char_pos(span.lo) } -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 size_and_align_of(cx: &mut CrateContext, llvm_type: Type) -> (uint, uint) { + (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type)) } fn bytes_to_bits(bytes: uint) -> c_ulonglong { diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 2cd313ff43154..0bf0a522a655f 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -113,3 +113,9 @@ pub fn llalign_of(cx: &CrateContext, ty: Type) -> ValueRef { llvm::LLVMAlignOf(ty.to_ref()), cx.int_type.to_ref(), False); } } + +pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: uint) -> uint { + unsafe { + return llvm::LLVMOffsetOfElement(cx.td.lltd, struct_ty.to_ref(), element as u32) as uint; + } +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 50f331f7e7d48..9451900091f3f 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -50,6 +50,8 @@ use syntax::opt_vec; use syntax::abi::AbiSet; use syntax; +pub static INITIAL_DISCRIMINANT_VALUE: int = 0; + // Data types #[deriving(Eq, IterBytes)] @@ -282,7 +284,7 @@ struct ctxt_ { needs_unwind_cleanup_cache: @mut HashMap, tc_cache: @mut HashMap, ast_ty_to_ty_cache: @mut HashMap, - enum_var_cache: @mut HashMap, + enum_var_cache: @mut HashMap, ty_param_defs: @mut HashMap, adjustments: @mut HashMap, normalized_cache: @mut HashMap, @@ -3692,8 +3694,9 @@ fn struct_ctor_id(cx: ctxt, struct_did: ast::def_id) -> Option { // Enum information #[deriving(Clone)] -pub struct VariantInfo_ { +pub struct VariantInfo { args: ~[t], + arg_names: Option<~[ast::ident]>, ctor_ty: t, name: ast::ident, id: ast::def_id, @@ -3701,19 +3704,71 @@ pub struct VariantInfo_ { vis: visibility } -pub type VariantInfo = @VariantInfo_; +impl VariantInfo { + + /// Creates a new VariantInfo from the corresponding ast representation. + /// + /// Does not do any caching of the value in the type context. + pub fn from_ast_variant(cx: ctxt, + ast_variant: &ast::variant, + discriminant: int) -> VariantInfo { + + let ctor_ty = node_id_to_type(cx, ast_variant.node.id); + + match ast_variant.node.kind { + ast::tuple_variant_kind(ref args) => { + let arg_tys = if args.len() > 0 { ty_fn_args(ctor_ty).map(|a| *a) } else { ~[] }; + + return VariantInfo { + args: arg_tys, + arg_names: None, + ctor_ty: ctor_ty, + name: ast_variant.node.name, + id: ast_util::local_def(ast_variant.node.id), + disr_val: discriminant, + vis: ast_variant.node.vis + }; + }, + ast::struct_variant_kind(ref struct_def) => { + + let fields: &[@struct_field] = struct_def.fields; + + assert!(fields.len() > 0); + + let arg_tys = ty_fn_args(ctor_ty).map(|a| *a); + let arg_names = do fields.map |field| { + match field.node.kind { + named_field(ident, _) => ident, + unnamed_field => cx.sess.bug( + "enum_variants: all fields in struct must have a name") + } + }; + + return VariantInfo { + args: arg_tys, + arg_names: Some(arg_names), + ctor_ty: ctor_ty, + name: ast_variant.node.name, + id: ast_util::local_def(ast_variant.node.id), + disr_val: discriminant, + vis: ast_variant.node.vis + }; + } + } + } +} pub fn substd_enum_variants(cx: ctxt, id: ast::def_id, substs: &substs) - -> ~[VariantInfo] { + -> ~[@VariantInfo] { do enum_variants(cx, id).iter().transform |variant_info| { let substd_args = variant_info.args.iter() .transform(|aty| subst(cx, substs, *aty)).collect(); let substd_ctor_ty = subst(cx, substs, variant_info.ctor_ty); - @VariantInfo_ { + @VariantInfo { args: substd_args, ctor_ty: substd_ctor_ty, ..(**variant_info).clone() @@ -3831,7 +3886,7 @@ pub fn type_is_empty(cx: ctxt, t: t) -> bool { } } -pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { +pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] { match cx.enum_var_cache.find(&id) { Some(&variants) => return variants, _ => { /* fallthrough */ } @@ -3850,61 +3905,31 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { node: ast::item_enum(ref enum_definition, _), _ }, _) => { - let mut disr_val = -1; + let mut last_discriminant: Option = None; @enum_definition.variants.iter().transform(|variant| { - let ctor_ty = node_id_to_type(cx, variant.node.id); - - match variant.node.kind { - ast::tuple_variant_kind(ref args) => { - let arg_tys = if args.len() > 0u { - ty_fn_args(ctor_ty).map(|a| *a) } - else { - ~[] - }; - - match variant.node.disr_expr { - Some (ex) => { - disr_val = match const_eval::eval_const_expr(cx, - ex) { - const_eval::const_int(val) => val as int, - _ => cx.sess.bug("enum_variants: bad disr expr") - } - } - _ => disr_val += 1 + let mut discriminant = match last_discriminant { + Some(val) => val + 1, + None => INITIAL_DISCRIMINANT_VALUE + }; + + match variant.node.disr_expr { + Some(e) => match const_eval::eval_const_expr_partial(&cx, e) { + Ok(const_eval::const_int(val)) => discriminant = val as int, + Ok(_) => { + cx.sess.span_err(e.span, "expected signed integer constant"); } - @VariantInfo_{ - args: arg_tys, - ctor_ty: ctor_ty, - name: variant.node.name, - id: ast_util::local_def(variant.node.id), - disr_val: disr_val, - vis: variant.node.vis - } - }, - ast::struct_variant_kind(struct_def) => { - let arg_tys = - // Is this check needed for structs too, or are they always guaranteed - // to have a valid constructor function? - if struct_def.fields.len() > 0 { - ty_fn_args(ctor_ty).map(|a| *a) - } else { - ~[] - }; - - assert!(variant.node.disr_expr.is_none()); - disr_val += 1; - - @VariantInfo_{ - args: arg_tys, - ctor_ty: ctor_ty, - name: variant.node.name, - id: ast_util::local_def(variant.node.id), - disr_val: disr_val, - vis: variant.node.vis + Err(ref err) => { + cx.sess.span_err(e.span, fmt!("expected constant: %s", (*err))); } - } - } + }, + None => {} + }; + + let variant_info = @VariantInfo::from_ast_variant(cx, variant, discriminant); + last_discriminant = Some(discriminant); + variant_info + }).collect() } _ => cx.sess.bug("enum_variants: id not bound to an enum") @@ -3919,7 +3944,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { pub fn enum_variant_with_id(cx: ctxt, enum_id: ast::def_id, variant_id: ast::def_id) - -> VariantInfo { + -> @VariantInfo { let variants = enum_variants(cx, enum_id); let mut i = 0; while i < variants.len() { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 4a9e0fddbe73a..fa24c8c6d0983 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -81,7 +81,7 @@ use middle::const_eval; use middle::pat_util::pat_id_map; use middle::pat_util; use middle::lint::unreachable_code; -use middle::ty::{FnSig, VariantInfo_}; +use middle::ty::{FnSig, VariantInfo}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; use middle::ty::{substs, param_ty, ExprTyProvider}; use middle::ty; @@ -3133,82 +3133,66 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, vs: &[ast::variant], id: ast::node_id) { fn do_check(ccx: @mut CrateCtxt, - _sp: span, vs: &[ast::variant], - id: ast::node_id, - disr_vals: &mut ~[int], - disr_val: &mut int, - variants: &mut ~[ty::VariantInfo]) { + id: ast::node_id) + -> ~[@ty::VariantInfo] { + let rty = ty::node_id_to_type(ccx.tcx, id); - for vs.iter().advance |v| { - for v.node.disr_expr.iter().advance |e_ref| { - let e = *e_ref; - debug!("disr expr, checking %s", - pprust::expr_to_str(e, ccx.tcx.sess.intr())); - let declty = ty::mk_int(); - let fcx = blank_fn_ctxt(ccx, rty, e.id); - check_const_with_ty(fcx, e.span, e, declty); - // check_expr (from check_const pass) doesn't guarantee - // that the expression is in an form that eval_const_expr can - // handle, so we may still get an internal compiler error - - match const_eval::eval_const_expr_partial(&ccx.tcx, e) { - Ok(const_eval::const_int(val)) => { - *disr_val = val as int; - } - Ok(_) => { - ccx.tcx.sess.span_err(e.span, "expected signed integer \ - constant"); - } - Err(ref err) => { - ccx.tcx.sess.span_err(e.span, - fmt!("expected constant: %s", (*err))); + let mut variants: ~[@ty::VariantInfo] = ~[]; + let mut disr_vals: ~[int] = ~[]; + let mut prev_disr_val: Option = None; - } - } - } - if disr_vals.contains(&*disr_val) { - ccx.tcx.sess.span_err(v.span, - "discriminator value already exists"); - } - disr_vals.push(*disr_val); - let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id); + for vs.iter().advance |v| { - let this_disr_val = *disr_val; - *disr_val += 1; + // If the discriminant value is specified explicitly in the enum check whether the + // initialization expression is valid, otherwise use the last value plus one. + let mut current_disr_val = match prev_disr_val { + Some(prev_disr_val) => prev_disr_val + 1, + None => ty::INITIAL_DISCRIMINANT_VALUE + }; - let arg_tys = match v.node.kind { - ast::tuple_variant_kind(ref args) if args.len() > 0u => { - Some(ty::ty_fn_args(ctor_ty).map(|a| *a)) - } - ast::tuple_variant_kind(_) => { - Some(~[]) - } - ast::struct_variant_kind(_) => { - Some(ty::lookup_struct_fields( - ccx.tcx, local_def(v.node.id)).map(|cf| - ty::node_id_to_type(ccx.tcx, cf.id.node))) - } + match v.node.disr_expr { + Some(e) => { + debug!("disr expr, checking %s", pprust::expr_to_str(e, ccx.tcx.sess.intr())); + + let declty = ty::mk_int(); + let fcx = blank_fn_ctxt(ccx, rty, e.id); + check_const_with_ty(fcx, e.span, e, declty); + // check_expr (from check_const pass) doesn't guarantee + // that the expression is in an form that eval_const_expr can + // handle, so we may still get an internal compiler error + + match const_eval::eval_const_expr_partial(&ccx.tcx, e) { + Ok(const_eval::const_int(val)) => current_disr_val = val as int, + Ok(_) => { + ccx.tcx.sess.span_err(e.span, "expected signed integer constant"); + } + Err(ref err) => { + ccx.tcx.sess.span_err(e.span, fmt!("expected constant: %s", (*err))); + } + } + }, + None => () }; - match arg_tys { - None => {} - Some(arg_tys) => { - variants.push( - @VariantInfo_{args: arg_tys, ctor_ty: ctor_ty, - name: v.node.name, id: local_def(v.node.id), - disr_val: this_disr_val, vis: v.node.vis}); - } + // Check for duplicate discriminator values + if disr_vals.contains(¤t_disr_val) { + ccx.tcx.sess.span_err(v.span, "discriminator value already exists"); } + disr_vals.push(current_disr_val); + + let variant_info = @VariantInfo::from_ast_variant(ccx.tcx, v, current_disr_val); + prev_disr_val = Some(current_disr_val); + + variants.push(variant_info); } + + return variants; } let rty = ty::node_id_to_type(ccx.tcx, id); - let mut disr_vals: ~[int] = ~[]; - let mut disr_val = 0; - let mut variants = ~[]; - do_check(ccx, sp, vs, id, &mut disr_vals, &mut disr_val, &mut variants); + let variants = do_check(ccx, vs, id); // cache so that ty::enum_variants won't repeat this work ccx.tcx.enum_var_cache.insert(local_def(id), @variants); diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 614c1723c5fb7..2a1f26bf44108 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -565,8 +565,8 @@ extern "C" bool LLVMRustStartMultithreading() { typedef DIBuilder* DIBuilderRef; template -DIT unwrapDI(LLVMValueRef ref) { - return DIT(ref ? unwrap(ref) : NULL); +DIT unwrapDI(LLVMValueRef ref) { + return DIT(ref ? unwrap(ref) : NULL); } extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) { @@ -604,21 +604,21 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateFile( extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType( DIBuilderRef Builder, - LLVMValueRef File, + LLVMValueRef File, LLVMValueRef ParameterTypes) { return wrap(Builder->createSubroutineType( - unwrapDI(File), + unwrapDI(File), unwrapDI(ParameterTypes))); } extern "C" LLVMValueRef LLVMDIBuilderCreateFunction( DIBuilderRef Builder, - LLVMValueRef Scope, + LLVMValueRef Scope, const char* Name, const char* LinkageName, - LLVMValueRef File, + LLVMValueRef File, unsigned LineNo, - LLVMValueRef Ty, + LLVMValueRef Ty, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, @@ -628,11 +628,11 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateFunction( LLVMValueRef TParam, LLVMValueRef Decl) { return wrap(Builder->createFunction( - unwrapDI(Scope), Name, LinkageName, - unwrapDI(File), LineNo, - unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, + unwrapDI(Scope), Name, LinkageName, + unwrapDI(File), LineNo, + unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, - unwrap(Fn), + unwrap(Fn), unwrapDI(TParam), unwrapDI(Decl))); } @@ -644,10 +644,10 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateBasicType( uint64_t AlignInBits, unsigned Encoding) { return wrap(Builder->createBasicType( - Name, SizeInBits, + Name, SizeInBits, AlignInBits, Encoding)); } - + extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType( DIBuilderRef Builder, LLVMValueRef PointeeTy, @@ -672,11 +672,11 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateStructType( unsigned RunTimeLang, LLVMValueRef VTableHolder) { return wrap(Builder->createStructType( - unwrapDI(Scope), Name, - unwrapDI(File), LineNumber, - SizeInBits, AlignInBits, Flags, - unwrapDI(DerivedFrom), - unwrapDI(Elements), RunTimeLang, + unwrapDI(Scope), Name, + unwrapDI(File), LineNumber, + SizeInBits, AlignInBits, Flags, + unwrapDI(DerivedFrom), + unwrapDI(Elements), RunTimeLang, unwrapDI(VTableHolder))); } @@ -692,12 +692,12 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( unsigned Flags, LLVMValueRef Ty) { return wrap(Builder->createMemberType( - unwrapDI(Scope), Name, + unwrapDI(Scope), Name, unwrapDI(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, Flags, + SizeInBits, AlignInBits, OffsetInBits, Flags, unwrapDI(Ty))); } - + extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( DIBuilderRef Builder, LLVMValueRef Scope, @@ -705,10 +705,10 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( unsigned Line, unsigned Col) { return wrap(Builder->createLexicalBlock( - unwrapDI(Scope), + unwrapDI(Scope), unwrapDI(File), Line, Col)); } - + extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable( DIBuilderRef Builder, unsigned Tag, @@ -720,45 +720,45 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable( bool AlwaysPreserve, unsigned Flags, unsigned ArgNo) { - return wrap(Builder->createLocalVariable(Tag, - unwrapDI(Scope), Name, - unwrapDI(File), - LineNo, + 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, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, LLVMValueRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, - unwrapDI(Ty), + unwrapDI(Ty), unwrapDI(Subscripts))); } extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType( DIBuilderRef Builder, - uint64_t Size, - uint64_t AlignInBits, - LLVMValueRef Ty, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, LLVMValueRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, - unwrapDI(Ty), + unwrapDI(Ty), unwrapDI(Subscripts))); } extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange( - DIBuilderRef Builder, - int64_t Lo, + DIBuilderRef Builder, + int64_t Lo, int64_t Count) { return wrap(Builder->getOrCreateSubrange(Lo, Count)); } extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray( DIBuilderRef Builder, - LLVMValueRef* Ptr, + LLVMValueRef* Ptr, unsigned Count) { return wrap(Builder->getOrCreateArray( ArrayRef(reinterpret_cast(Ptr), Count))); @@ -770,8 +770,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMValueRef VarInfo, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI(VarInfo), + unwrap(Val), + unwrapDI(VarInfo), unwrap(InsertAtEnd))); } @@ -781,7 +781,61 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMValueRef VarInfo, LLVMValueRef InsertBefore) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI(VarInfo), + unwrap(Val), + unwrapDI(VarInfo), unwrap(InsertBefore))); } + +extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerator( + DIBuilderRef Builder, + const char* Name, + uint64_t Val) +{ + return wrap(Builder->createEnumerator(Name, Val)); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateEnumerationType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, + LLVMValueRef Elements, + LLVMValueRef ClassType) +{ + return wrap(Builder->createEnumerationType( + unwrapDI(Scope), + Name, + unwrapDI(File), + LineNumber, + SizeInBits, + AlignInBits, + unwrapDI(Elements), + unwrapDI(ClassType))); +} + +extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Flags, + LLVMValueRef Elements, + unsigned RunTimeLang) +{ + return wrap(Builder->createUnionType( + unwrapDI(Scope), + Name, + unwrapDI(File), + LineNumber, + SizeInBits, + AlignInBits, + Flags, + unwrapDI(Elements), + RunTimeLang)); +} \ No newline at end of file diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index d5f03ac604b76..5b6c3ed2f52f9 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -608,3 +608,6 @@ LLVMDIBuilderCreateSubroutineType LLVMDIBuilderGetOrCreateArray LLVMDIBuilderInsertDeclareAtEnd LLVMDIBuilderInsertDeclareBefore +LLVMDIBuilderCreateEnumerator +LLVMDIBuilderCreateEnumerationType +LLVMDIBuilderCreateUnionType diff --git a/src/test/debug-info/reference-to-basic.rs b/src/test/debug-info/borrowed-basic.rs similarity index 69% rename from src/test/debug-info/reference-to-basic.rs rename to src/test/debug-info/borrowed-basic.rs index dfd0fbf865557..7610301f6f035 100644 --- a/src/test/debug-info/reference-to-basic.rs +++ b/src/test/debug-info/borrowed-basic.rs @@ -10,10 +10,7 @@ // 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 -// doesn't seem to be any way around this. Also, gdb doesn't know -// about UTF-32 character encoding and will print a rust char as only +// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only // its numerical value. // compile-flags:-Z extra-debug-info @@ -67,49 +64,49 @@ fn main() { let bool_val: bool = true; - let bool_ref : &bool = &bool_val; + let bool_ref: &bool = &bool_val; let int_val: int = -1; - let int_ref : &int = &int_val; + let int_ref: &int = &int_val; let char_val: char = 'a'; - let char_ref : &char = &char_val; + let char_ref: &char = &char_val; let i8_val: i8 = 68; - let i8_ref : &i8 = &i8_val; + let i8_ref: &i8 = &i8_val; let i16_val: i16 = -16; - let i16_ref : &i16 = &i16_val; + let i16_ref: &i16 = &i16_val; let i32_val: i32 = -32; - let i32_ref : &i32 = &i32_val; + let i32_ref: &i32 = &i32_val; let uint_val: i64 = -64; - let i64_ref : &i64 = &uint_val; + let i64_ref: &i64 = &uint_val; let uint_val: uint = 1; - let uint_ref : &uint = &uint_val; + let uint_ref: &uint = &uint_val; let u8_val: u8 = 100; - let u8_ref : &u8 = &u8_val; + let u8_ref: &u8 = &u8_val; let u16_val: u16 = 16; - let u16_ref : &u16 = &u16_val; + let u16_ref: &u16 = &u16_val; let u32_val: u32 = 32; - let u32_ref : &u32 = &u32_val; + let u32_ref: &u32 = &u32_val; let u64_val: u64 = 64; - let u64_ref : &u64 = &u64_val; + let u64_ref: &u64 = &u64_val; let float_val: float = 1.5; - let float_ref : &float = &float_val; + let float_ref: &float = &float_val; let f32_val: f32 = 2.5; - let f32_ref : &f32 = &f32_val; + let f32_ref: &f32 = &f32_val; let f64_val: f64 = 3.5; - let f64_ref : &f64 = &f64_val; + let f64_ref: &f64 = &f64_val; zzz(); } diff --git a/src/test/debug-info/borrowed-c-style-enum.rs b/src/test/debug-info/borrowed-c-style-enum.rs new file mode 100644 index 0000000000000..70c85258c7921 --- /dev/null +++ b/src/test/debug-info/borrowed-c-style-enum.rs @@ -0,0 +1,42 @@ +// 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 or the MIT license +// , 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 *the_a_ref +// check:$1 = TheA + +// debugger:print *the_b_ref +// check:$2 = TheB + +// debugger:print *the_c_ref +// check:$3 = TheC + +enum ABC { TheA, TheB, TheC } + +fn main() { + let the_a = TheA; + let the_a_ref: &ABC = &the_a; + + let the_b = TheB; + let the_b_ref: &ABC = &the_b; + + let the_c = TheC; + let the_c_ref: &ABC = &the_c; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/borrowed-enum.rs b/src/test/debug-info/borrowed-enum.rs new file mode 100644 index 0000000000000..38aa9c3881000 --- /dev/null +++ b/src/test/debug-info/borrowed-enum.rs @@ -0,0 +1,62 @@ +// 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 or the MIT license +// , 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 *the_a_ref +// check:$1 = {{TheA, x = 0, y = 8970181431921507452}, {TheA, 0, 2088533116, 2088533116}} + +// debugger:print *the_b_ref +// check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}} + +// debugger:print *univariant_ref +// check:$3 = {4820353753753434} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum ABC { + TheA { x: i64, y: i64 }, + TheB (i64, i32, i32), +} + +// This is a special case since it does not have the implicit discriminant field. +enum Univariant { + TheOnlyCase(i64) +} + +fn main() { + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + let the_a = TheA { x: 0, y: 8970181431921507452 }; + let the_a_ref: &ABC = &the_a; + + // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 + // 0b00010001000100010001000100010001 = 286331153 + // 0b0001000100010001 = 4369 + // 0b00010001 = 17 + let the_b = TheB (0, 286331153, 286331153); + let the_b_ref: &ABC = &the_b; + + let univariant = TheOnlyCase(4820353753753434); + let univariant_ref: &Univariant = &univariant; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/reference-to-managed-basic.rs b/src/test/debug-info/borrowed-managed-basic.rs similarity index 79% rename from src/test/debug-info/reference-to-managed-basic.rs rename to src/test/debug-info/borrowed-managed-basic.rs index e3951c94b6f86..9087bb36fa5d6 100644 --- a/src/test/debug-info/reference-to-managed-basic.rs +++ b/src/test/debug-info/borrowed-managed-basic.rs @@ -65,49 +65,49 @@ fn main() { let bool_box: @bool = @true; - let bool_ref : &bool = bool_box; + let bool_ref: &bool = bool_box; let int_box: @int = @-1; - let int_ref : &int = int_box; + let int_ref: &int = int_box; let char_box: @char = @'a'; - let char_ref : &char = char_box; + let char_ref: &char = char_box; let i8_box: @i8 = @68; - let i8_ref : &i8 = i8_box; + let i8_ref: &i8 = i8_box; let i16_box: @i16 = @-16; - let i16_ref : &i16 = i16_box; + let i16_ref: &i16 = i16_box; let i32_box: @i32 = @-32; - let i32_ref : &i32 = i32_box; + let i32_ref: &i32 = i32_box; let i64_box: @i64 = @-64; - let i64_ref : &i64 = i64_box; + let i64_ref: &i64 = i64_box; let uint_box: @uint = @1; - let uint_ref : &uint = uint_box; + let uint_ref: &uint = uint_box; let u8_box: @u8 = @100; - let u8_ref : &u8 = u8_box; + let u8_ref: &u8 = u8_box; let u16_box: @u16 = @16; - let u16_ref : &u16 = u16_box; + let u16_ref: &u16 = u16_box; let u32_box: @u32 = @32; - let u32_ref : &u32 = u32_box; + let u32_ref: &u32 = u32_box; let u64_box: @u64 = @64; - let u64_ref : &u64 = u64_box; + let u64_ref: &u64 = u64_box; let float_box: @float = @1.5; - let float_ref : &float = float_box; + let float_ref: &float = float_box; let f32_box: @f32 = @2.5; - let f32_ref : &f32 = f32_box; + let f32_ref: &f32 = f32_box; let f64_box: @f64 = @3.5; - let f64_ref : &f64 = f64_box; + let f64_ref: &f64 = f64_box; zzz(); } diff --git a/src/test/debug-info/reference-to-struct.rs b/src/test/debug-info/borrowed-struct.rs similarity index 69% rename from src/test/debug-info/reference-to-struct.rs rename to src/test/debug-info/borrowed-struct.rs index f00872c00b0e4..8b6eca3e37f79 100644 --- a/src/test/debug-info/reference-to-struct.rs +++ b/src/test/debug-info/borrowed-struct.rs @@ -10,9 +10,6 @@ // xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 -// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical -// value. - // compile-flags:-Z extra-debug-info // debugger:break zzz // debugger:run @@ -57,20 +54,20 @@ struct SomeStruct { fn main() { let stack_val: SomeStruct = SomeStruct { x: 10, y: 23.5 }; - let stack_val_ref : &SomeStruct = &stack_val; - let stack_val_interior_ref_1 : &int = &stack_val.x; - let stack_val_interior_ref_2 : &f64 = &stack_val.y; - let ref_to_unnamed : &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; + let stack_val_ref: &SomeStruct = &stack_val; + let stack_val_interior_ref_1: &int = &stack_val.x; + let stack_val_interior_ref_2: &f64 = &stack_val.y; + let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; let managed_val = @SomeStruct { x: 12, y: 25.5 }; - let managed_val_ref : &SomeStruct = managed_val; - let managed_val_interior_ref_1 : &int = &managed_val.x; - let managed_val_interior_ref_2 : &f64 = &managed_val.y; + let managed_val_ref: &SomeStruct = managed_val; + let managed_val_interior_ref_1: &int = &managed_val.x; + let managed_val_interior_ref_2: &f64 = &managed_val.y; let unique_val = ~SomeStruct { x: 13, y: 26.5 }; - let unique_val_ref : &SomeStruct = unique_val; - let unique_val_interior_ref_1 : &int = &unique_val.x; - let unique_val_interior_ref_2 : &f64 = &unique_val.y; + let unique_val_ref: &SomeStruct = unique_val; + let unique_val_interior_ref_1: &int = &unique_val.x; + let unique_val_interior_ref_2: &f64 = &unique_val.y; zzz(); } diff --git a/src/test/debug-info/reference-to-tuple.rs b/src/test/debug-info/borrowed-tuple.rs similarity index 73% rename from src/test/debug-info/reference-to-tuple.rs rename to src/test/debug-info/borrowed-tuple.rs index 86d02185bdae7..da199941c8419 100644 --- a/src/test/debug-info/reference-to-tuple.rs +++ b/src/test/debug-info/borrowed-tuple.rs @@ -10,9 +10,6 @@ // xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 -// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical -// value. - // compile-flags:-Z extra-debug-info // debugger:break zzz // debugger:run @@ -32,14 +29,14 @@ fn main() { let stack_val: (i16, f32) = (-14, -19f32); - let stack_val_ref : &(i16, f32) = &stack_val; - let ref_to_unnamed : &(i16, f32) = &(-15, -20f32); + let stack_val_ref: &(i16, f32) = &stack_val; + let ref_to_unnamed: &(i16, f32) = &(-15, -20f32); - let managed_val : @(i16, f32) = @(-16, -21f32); - let managed_val_ref : &(i16, f32) = managed_val; + let managed_val: @(i16, f32) = @(-16, -21f32); + let managed_val_ref: &(i16, f32) = managed_val; let unique_val: ~(i16, f32) = ~(-17, -22f32); - let unique_val_ref : &(i16, f32) = unique_val; + let unique_val_ref: &(i16, f32) = unique_val; zzz(); } diff --git a/src/test/debug-info/reference-to-unique-basic.rs b/src/test/debug-info/borrowed-unique-basic.rs similarity index 75% rename from src/test/debug-info/reference-to-unique-basic.rs rename to src/test/debug-info/borrowed-unique-basic.rs index ce5b50459f660..52f5a2cba1ebe 100644 --- a/src/test/debug-info/reference-to-unique-basic.rs +++ b/src/test/debug-info/borrowed-unique-basic.rs @@ -10,8 +10,7 @@ // xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 -// Gdb doesn't know -// about UTF-32 character encoding and will print a rust char as only +// Gdb doesn't know about UTF-32 character encoding and will print a rust char as only // its numerical value. // compile-flags:-Z extra-debug-info @@ -66,49 +65,49 @@ fn main() { let bool_box: ~bool = ~true; - let bool_ref : &bool = bool_box; + let bool_ref: &bool = bool_box; let int_box: ~int = ~-1; - let int_ref : &int = int_box; + let int_ref: &int = int_box; let char_box: ~char = ~'a'; - let char_ref : &char = char_box; + let char_ref: &char = char_box; let i8_box: ~i8 = ~68; - let i8_ref : &i8 = i8_box; + let i8_ref: &i8 = i8_box; let i16_box: ~i16 = ~-16; - let i16_ref : &i16 = i16_box; + let i16_ref: &i16 = i16_box; let i32_box: ~i32 = ~-32; - let i32_ref : &i32 = i32_box; + let i32_ref: &i32 = i32_box; let i64_box: ~i64 = ~-64; - let i64_ref : &i64 = i64_box; + let i64_ref: &i64 = i64_box; let uint_box: ~uint = ~1; - let uint_ref : &uint = uint_box; + let uint_ref: &uint = uint_box; let u8_box: ~u8 = ~100; - let u8_ref : &u8 = u8_box; + let u8_ref: &u8 = u8_box; let u16_box: ~u16 = ~16; - let u16_ref : &u16 = u16_box; + let u16_ref: &u16 = u16_box; let u32_box: ~u32 = ~32; - let u32_ref : &u32 = u32_box; + let u32_ref: &u32 = u32_box; let u64_box: ~u64 = ~64; - let u64_ref : &u64 = u64_box; + let u64_ref: &u64 = u64_box; let float_box: ~float = ~1.5; - let float_ref : &float = float_box; + let float_ref: &float = float_box; let f32_box: ~f32 = ~2.5; - let f32_ref : &f32 = f32_box; + let f32_ref: &f32 = f32_box; let f64_box: ~f64 = ~3.5; - let f64_ref : &f64 = f64_box; + let f64_ref: &f64 = f64_box; zzz(); } diff --git a/src/test/debug-info/box.rs b/src/test/debug-info/box.rs index 4a3a65a90550c..c63cffd7b74bb 100644 --- a/src/test/debug-info/box.rs +++ b/src/test/debug-info/box.rs @@ -8,20 +8,20 @@ // 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 _zzz // debugger:run // debugger:finish -// debugger:print a->boxed +// debugger:print *a // check:$1 = 1 -// debugger:print b->boxed +// debugger:print *b // check:$2 = {2, 3.5} -// debugger:print c->boxed +// debugger:print c->val // check:$3 = 4 -// debugger:print d->boxed +// debugger:print d->val // check:$4 = false fn main() { diff --git a/src/test/debug-info/boxed-struct.rs b/src/test/debug-info/boxed-struct.rs new file mode 100644 index 0000000000000..86162f0fa04cd --- /dev/null +++ b/src/test/debug-info/boxed-struct.rs @@ -0,0 +1,59 @@ +// 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 or the MIT license +// , 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 *unique +// check:$1 = {x = 99, y = 999, z = 9999, w = 99999} + +// debugger:print managed->val +// check:$2 = {x = 88, y = 888, z = 8888, w = 88888} + +// debugger:print *unique_dtor +// check:$3 = {x = 77, y = 777, z = 7777, w = 77777} + +// debugger:print managed_dtor->val +// check:$4 = {x = 33, y = 333, z = 3333, w = 33333} + +struct StructWithSomePadding { + x: i16, + y: i32, + z: i32, + w: i64 +} + +struct StructWithDestructor { + x: i16, + y: i32, + z: i32, + w: i64 +} + +impl Drop for StructWithDestructor { + fn drop(&self) {} +} + +fn main() { + + let unique = ~StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; + let managed = @StructWithSomePadding { x: 88, y: 888, z: 8888, w: 88888 }; + + let unique_dtor = ~StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; + let managed_dtor = @StructWithDestructor { x: 33, y: 333, z: 3333, w: 33333 }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/boxed-vec.rs b/src/test/debug-info/boxed-vec.rs new file mode 100644 index 0000000000000..8abead6519697 --- /dev/null +++ b/src/test/debug-info/boxed-vec.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , 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 managed->val.fill +// check:$1 = 24 +// debugger:print *((uint64_t[3]*)(managed->val.elements)) +// check:$2 = {7, 8, 9} + +// debugger:print unique->fill +// check:$3 = 32 +// debugger:print *((uint64_t[4]*)(unique->elements)) +// check:$4 = {10, 11, 12, 13} + +fn main() { + + let managed: @[i64] = @[7, 8, 9]; + let unique: ~[i64] = ~[10, 11, 12, 13]; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/c-style-enum-in-composite.rs b/src/test/debug-info/c-style-enum-in-composite.rs new file mode 100644 index 0000000000000..47e433ea814ab --- /dev/null +++ b/src/test/debug-info/c-style-enum-in-composite.rs @@ -0,0 +1,119 @@ +// 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 or the MIT license +// , 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 tuple_interior_padding +// check:$1 = {0, OneHundred} + +// debugger:print tuple_padding_at_end +// check:$2 = {{1, OneThousand}, 2} + +// debugger:print tuple_different_enums +// check:$3 = {OneThousand, MountainView, OneMillion, Vienna} + +// debugger:print padded_struct +// check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5} + +// debugger:print packed_struct +// check:$5 = {a = 6, b = OneHundred, c = 7, d = Vienna, e = 8} + +// debugger:print non_padded_struct +// check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto} + +// debugger:print struct_with_drop +// check:$7 = {{a = OneHundred, b = Vienna}, 9} + +enum AnEnum { + OneHundred = 100, + OneThousand = 1000, + OneMillion = 1000000 +} + +enum AnotherEnum { + MountainView, + Toronto, + Vienna +} + +struct PaddedStruct { + a: i16, + b: AnEnum, + c: i16, + d: AnotherEnum, + e: i16 +} + +#[packed] +struct PackedStruct { + a: i16, + b: AnEnum, + c: i16, + d: AnotherEnum, + e: i16 +} + +struct NonPaddedStruct { + a: AnEnum, + b: AnotherEnum, + c: AnEnum, + d: AnotherEnum +} + +struct StructWithDrop { + a: AnEnum, + b: AnotherEnum +} + +impl Drop for StructWithDrop { + fn drop(&self) {()} +} + +fn main() { + + let tuple_interior_padding = (0_i16, OneHundred); + // It will depend on the machine architecture if any padding is actually involved here + let tuple_padding_at_end = ((1_u64, OneThousand), 2_u64); + let tuple_different_enums = (OneThousand, MountainView, OneMillion, Vienna); + + let padded_struct = PaddedStruct { + a: 3, + b: OneMillion, + c: 4, + d: Toronto, + e: 5 + }; + + let packed_struct = PackedStruct { + a: 6, + b: OneHundred, + c: 7, + d: Vienna, + e: 8 + }; + + let non_padded_struct = NonPaddedStruct { + a: OneMillion, + b: MountainView, + c: OneThousand, + d: Toronto + }; + + let struct_with_drop = (StructWithDrop { a: OneHundred, b: Vienna }, 9_i64); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/c-style-enum.rs b/src/test/debug-info/c-style-enum.rs new file mode 100644 index 0000000000000..d7cce4e6f3fb5 --- /dev/null +++ b/src/test/debug-info/c-style-enum.rs @@ -0,0 +1,70 @@ +// 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 or the MIT license +// , 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 auto_one +// check:$1 = One + +// debugger:print auto_two +// check:$2 = Two + +// debugger:print auto_three +// check:$3 = Three + +// debugger:print manual_one_hundred +// check:$4 = OneHundred + +// debugger:print manual_one_thousand +// check:$5 = OneThousand + +// debugger:print manual_one_million +// check:$6 = OneMillion + +// debugger:print single_variant +// check:$7 = TheOnlyVariant + +enum AutoDiscriminant { + One, + Two, + Three +} + +enum ManualDiscriminant { + OneHundred = 100, + OneThousand = 1000, + OneMillion = 1000000 +} + +enum SingleVariant { + TheOnlyVariant +} + +fn main() { + + let auto_one = One; + let auto_two = Two; + let auto_three = Three; + + let manual_one_hundred = OneHundred; + let manual_one_thousand = OneThousand; + let manual_one_million = OneMillion; + + let single_variant = TheOnlyVariant; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/destructured-local.rs b/src/test/debug-info/destructured-local.rs index bf53d95b588d0..207899fe3b510 100644 --- a/src/test/debug-info/destructured-local.rs +++ b/src/test/debug-info/destructured-local.rs @@ -10,9 +10,6 @@ // xfail-test -// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical -// value. - // compile-flags:-Z extra-debug-info // debugger:break zzz // debugger:run @@ -25,7 +22,7 @@ // check:$2 = false fn main() { - let (a, b) : (int, bool) = (9898, false); + let (a, b): (int, bool) = (9898, false); zzz(); } diff --git a/src/test/debug-info/evec-in-struct.rs b/src/test/debug-info/evec-in-struct.rs new file mode 100644 index 0000000000000..7e42690548e70 --- /dev/null +++ b/src/test/debug-info/evec-in-struct.rs @@ -0,0 +1,88 @@ +// 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 or the MIT license +// , 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:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print no_padding1 +// check:$1 = {x = {0, 1, 2}, y = -3, z = {4.5, 5.5}} +// debugger:print no_padding2 +// check:$2 = {x = {6, 7, 8}, y = {{9, 10}, {11, 12}}} + +// debugger:print struct_internal_padding +// check:$3 = {x = {13, 14}, y = {15, 16}} + +// debugger:print single_vec +// check:$4 = {x = {17, 18, 19, 20, 21}} + +// debugger:print struct_padded_at_end +// check:$5 = {x = {22, 23}, y = {24, 25}} + +struct NoPadding1 { + x: [u32, ..3], + y: i32, + z: [f32, ..2] +} + +struct NoPadding2 { + x: [u32, ..3], + y: [[u32, ..2], ..2] +} + +struct StructInternalPadding { + x: [i16, ..2], + y: [i64, ..2] +} + +struct SingleVec { + x: [i16, ..5] +} + +struct StructPaddedAtEnd { + x: [i64, ..2], + y: [i16, ..2] +} + +fn main() { + + let no_padding1 = NoPadding1 { + x: [0, 1, 2], + y: -3, + z: [4.5, 5.5] + }; + + let no_padding2 = NoPadding2 { + x: [6, 7, 8], + y: [[9, 10], [11, 12]] + }; + + let struct_internal_padding = StructInternalPadding { + x: [13, 14], + y: [15, 16] + }; + + let single_vec = SingleVec { + x: [17, 18, 19, 20, 21] + }; + + let struct_padded_at_end = StructPaddedAtEnd { + x: [22, 23], + y: [24, 25] + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/function-arguments.rs b/src/test/debug-info/function-arguments.rs index f5563cda259e9..225dfedfec721 100644 --- a/src/test/debug-info/function-arguments.rs +++ b/src/test/debug-info/function-arguments.rs @@ -10,9 +10,6 @@ // xfail-test -// GDB doesn't know about UTF-32 character encoding and will print a rust char as only its numerical -// value. - // compile-flags:-Z extra-debug-info // debugger:break zzz // debugger:run diff --git a/src/test/debug-info/managed-enum.rs b/src/test/debug-info/managed-enum.rs new file mode 100644 index 0000000000000..1a3600a7d8cb3 --- /dev/null +++ b/src/test/debug-info/managed-enum.rs @@ -0,0 +1,63 @@ +// 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 or the MIT license +// , 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 the_a->val +// check:$1 = {{TheA, x = 0, y = 8970181431921507452}, {TheA, 0, 2088533116, 2088533116}} + +// debugger:print the_b->val +// check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}} + +// debugger:print univariant->val +// check:$3 = {-9747455} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum ABC { + TheA { x: i64, y: i64 }, + TheB (i64, i32, i32), +} + +// This is a special case since it does not have the implicit discriminant field. +enum Univariant { + TheOnlyCase(i64) +} + +fn main() { + + // In order to avoid endianess trouble all of the following test values consist of a single + // repeated byte. This way each interpretation of the union should look the same, no matter if + // this is a big or little endian machine. + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + let the_a = @TheA { x: 0, y: 8970181431921507452 }; + + // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 + // 0b00010001000100010001000100010001 = 286331153 + // 0b0001000100010001 = 4369 + // 0b00010001 = 17 + let the_b = @TheB (0, 286331153, 286331153); + + let univariant = @TheOnlyCase(-9747455); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/managed-pointer-within-unique-vec.rs b/src/test/debug-info/managed-pointer-within-unique-vec.rs new file mode 100644 index 0000000000000..e42631599a9b9 --- /dev/null +++ b/src/test/debug-info/managed-pointer-within-unique-vec.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , 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 unique->val.elements[0]->val +// check:$1 = 10 + +// debugger:print unique->val.elements[1]->val +// check:$2 = 11 + +// debugger:print unique->val.elements[2]->val +// check:$3 = 12 + +// debugger:print unique->val.elements[3]->val +// check:$4 = 13 + +fn main() { + + let unique: ~[@i64] = ~[@10, @11, @12, @13]; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/managed-pointer-within-unique.rs b/src/test/debug-info/managed-pointer-within-unique.rs new file mode 100644 index 0000000000000..3eb1c2ef01e55 --- /dev/null +++ b/src/test/debug-info/managed-pointer-within-unique.rs @@ -0,0 +1,47 @@ +// 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 or the MIT license +// , 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:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *ordinary_unique +// check:$1 = {-1, -2} + +// debugger:print managed_within_unique.val->x +// check:$2 = -3 + +// debugger:print managed_within_unique.val->y->val +// check:$3 = -4 + +struct ContainsManaged +{ + x: int, + y: @int +} + +fn main() { + + let ordinary_unique = ~(-1, -2); + + + // This is a special case: Normally values allocated in the exchange heap are not boxed, unless, + // however, if they contain managed pointers. + // This test case verifies that both cases are handled correctly. + let managed_within_unique = ~ContainsManaged { x: -3, y: @-4 }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/nil-enum.rs b/src/test/debug-info/nil-enum.rs new file mode 100644 index 0000000000000..d3afd4b11f9cd --- /dev/null +++ b/src/test/debug-info/nil-enum.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , 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 first +// check:$1 = {} + +// debugger:print second +// check:$2 = {} + +enum ANilEnum {} +enum AnotherNilEnum {} + +// I (mw) am not sure this test case makes much sense... +// Also, it relies on some implementation details: +// 1. That empty enums as well as '()' are represented as empty structs +// 2. That gdb prints the string "{}" for empty structs (which may change some time) +fn main() { + unsafe { + let first: ANilEnum = std::cast::transmute(()); + let second: AnotherNilEnum = std::cast::transmute(()); + + zzz(); + } +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/option-like-enum.rs b/src/test/debug-info/option-like-enum.rs new file mode 100644 index 0000000000000..6d3b157d63e80 --- /dev/null +++ b/src/test/debug-info/option-like-enum.rs @@ -0,0 +1,71 @@ +// 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 or the MIT license +// , 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 some +// check:$1 = {0x12345678} + +// debugger:print none +// check:$2 = {0x0} + +// debugger:print full +// check:$3 = {454545, 0x87654321, 9988} + +// debugger:print empty +// check:$4 = {0, 0x0, 0} + +// debugger:print droid +// check:$5 = {id = 675675, range = 10000001, internals = 0x43218765} + +// debugger:print void_droid +// check:$6 = {id = 0, range = 0, internals = 0x0} + + +// If a struct has exactly two variants, one of them is empty, and the other one +// contains a non-nullable pointer, then this value is used as the discriminator. +// The test cases in this file make sure that something readable is generated for +// this kind of types. + +enum MoreFields<'self> { + Full(u32, &'self int, i16), + Empty +} + +enum NamedFields<'self> { + Droid { id: i32, range: i64, internals: &'self int }, + Void +} + +fn main() { + + let some: Option<&u32> = Some(unsafe { std::cast::transmute(0x12345678) }); + let none: Option<&u32> = None; + + let full = Full(454545, unsafe { std::cast::transmute(0x87654321) }, 9988); + + let int_val = 0; + let mut empty = Full(0, &int_val, 0); + empty = Empty; + + let droid = Droid { id: 675675, range: 10000001, internals: unsafe { std::cast::transmute(0x43218765) } }; + + let mut void_droid = Droid { id: 0, range: 0, internals: &int_val }; + void_droid = Void; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/packed-struct-with-destructor.rs b/src/test/debug-info/packed-struct-with-destructor.rs new file mode 100644 index 0000000000000..9ff91aa00d1c9 --- /dev/null +++ b/src/test/debug-info/packed-struct-with-destructor.rs @@ -0,0 +1,219 @@ +// 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 or the MIT license +// , 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:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print packed +// check:$1 = {x = 123, y = 234, z = 345} + +// debugger:print packedInPacked +// check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} + +// debugger:print packedInUnpacked +// check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} + +// debugger:print unpackedInPacked +// check:$4 = {a = 987, b = {x = 876, y = 765, z = 654}, c = {x = 543, y = 432, z = 321}, d = 210} + + +// debugger:print packedInPackedWithDrop +// check:$5 = {a = 11, b = {x = 22, y = 33, z = 44}, c = 55, d = {x = 66, y = 77, z = 88}} + +// debugger:print packedInUnpackedWithDrop +// check:$6 = {a = -11, b = {x = -22, y = -33, z = -44}, c = -55, d = {x = -66, y = -77, z = -88}} + +// debugger:print unpackedInPackedWithDrop +// check:$7 = {a = 98, b = {x = 87, y = 76, z = 65}, c = {x = 54, y = 43, z = 32}, d = 21} + +// debugger:print deeplyNested +// check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}} + +#[packed] +struct Packed { + x: i16, + y: i32, + z: i64 +} + +impl Drop for Packed { + fn drop(&self) {} +} + +#[packed] +struct PackedInPacked { + a: i32, + b: Packed, + c: i64, + d: Packed +} + +struct PackedInUnpacked { + a: i32, + b: Packed, + c: i64, + d: Packed +} + +struct Unpacked { + x: i64, + y: i32, + z: i16 +} + +impl Drop for Unpacked { + fn drop(&self) {} +} + +#[packed] +struct UnpackedInPacked { + a: i16, + b: Unpacked, + c: Unpacked, + d: i64 +} + +#[packed] +struct PackedInPackedWithDrop { + a: i32, + b: Packed, + c: i64, + d: Packed +} + +impl Drop for PackedInPackedWithDrop { + fn drop(&self) {} +} + +struct PackedInUnpackedWithDrop { + a: i32, + b: Packed, + c: i64, + d: Packed +} + +impl Drop for PackedInUnpackedWithDrop { + fn drop(&self) {} +} + +#[packed] +struct UnpackedInPackedWithDrop { + a: i16, + b: Unpacked, + c: Unpacked, + d: i64 +} + +impl Drop for UnpackedInPackedWithDrop { + fn drop(&self) {} +} + +struct DeeplyNested { + a: PackedInPacked, + b: UnpackedInPackedWithDrop, + c: PackedInUnpacked, + d: PackedInUnpackedWithDrop, + e: UnpackedInPacked, + f: PackedInPackedWithDrop +} + +fn main() { + let packed = Packed { x: 123, y: 234, z: 345 }; + + let packedInPacked = PackedInPacked { + a: 1111, + b: Packed { x: 2222, y: 3333, z: 4444 }, + c: 5555, + d: Packed { x: 6666, y: 7777, z: 8888 } + }; + + let packedInUnpacked = PackedInUnpacked { + a: -1111, + b: Packed { x: -2222, y: -3333, z: -4444 }, + c: -5555, + d: Packed { x: -6666, y: -7777, z: -8888 } + }; + + let unpackedInPacked = UnpackedInPacked { + a: 987, + b: Unpacked { x: 876, y: 765, z: 654 }, + c: Unpacked { x: 543, y: 432, z: 321 }, + d: 210 + }; + + let packedInPackedWithDrop = PackedInPackedWithDrop { + a: 11, + b: Packed { x: 22, y: 33, z: 44 }, + c: 55, + d: Packed { x: 66, y: 77, z: 88 } + }; + + let packedInUnpackedWithDrop = PackedInUnpackedWithDrop { + a: -11, + b: Packed { x: -22, y: -33, z: -44 }, + c: -55, + d: Packed { x: -66, y: -77, z: -88 } + }; + + let unpackedInPackedWithDrop = UnpackedInPackedWithDrop { + a: 98, + b: Unpacked { x: 87, y: 76, z: 65 }, + c: Unpacked { x: 54, y: 43, z: 32 }, + d: 21 + }; + + let deeplyNested = DeeplyNested { + a: PackedInPacked { + a: 1, + b: Packed { x: 2, y: 3, z: 4 }, + c: 5, + d: Packed { x: 6, y: 7, z: 8 } + }, + b: UnpackedInPackedWithDrop { + a: 9, + b: Unpacked { x: 10, y: 11, z: 12 }, + c: Unpacked { x: 13, y: 14, z: 15 }, + d: 16 + }, + c: PackedInUnpacked { + a: 17, + b: Packed { x: 18, y: 19, z: 20 }, + c: 21, + d: Packed { x: 22, y: 23, z: 24 } + }, + d: PackedInUnpackedWithDrop { + a: 25, + b: Packed { x: 26, y: 27, z: 28 }, + c: 29, + d: Packed { x: 30, y: 31, z: 32 } + }, + e: UnpackedInPacked { + a: 33, + b: Unpacked { x: 34, y: 35, z: 36 }, + c: Unpacked { x: 37, y: 38, z: 39 }, + d: 40 + }, + f: PackedInPackedWithDrop { + a: 41, + b: Packed { x: 42, y: 43, z: 44 }, + c: 45, + d: Packed { x: 46, y: 47, z: 48 } + } + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/packed-struct.rs b/src/test/debug-info/packed-struct.rs new file mode 100644 index 0000000000000..859166cb023a3 --- /dev/null +++ b/src/test/debug-info/packed-struct.rs @@ -0,0 +1,104 @@ +// 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 or the MIT license +// , 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:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print packed +// check:$1 = {x = 123, y = 234, z = 345} + +// debugger:print packedInPacked +// check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} + +// debugger:print packedInUnpacked +// check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} + +// debugger:print unpackedInPacked +// check:$4 = {a = 987, b = {x = 876, y = 765, z = 654, w = 543}, c = {x = 432, y = 321, z = 210, w = 109}, d = -98} + +// debugger:print sizeof(packed) +// check:$5 = 14 + +// debugger:print sizeof(packedInPacked) +// check:$6 = 40 + +#[packed] +struct Packed { + x: i16, + y: i32, + z: i64 +} + +#[packed] +struct PackedInPacked { + a: i32, + b: Packed, + c: i64, + d: Packed +} + +// layout (64 bit): aaaa bbbb bbbb bbbb bb.. .... cccc cccc dddd dddd dddd dd.. +struct PackedInUnpacked { + a: i32, + b: Packed, + c: i64, + d: Packed +} + +// layout (64 bit): xx.. yyyy zz.. .... wwww wwww +struct Unpacked { + x: i16, + y: i32, + z: i16, + w: i64 +} + +// layout (64 bit): aabb bbbb bbbb bbbb bbbb bbbb bbcc cccc cccc cccc cccc cccc ccdd dddd dd +#[packed] +struct UnpackedInPacked { + a: i16, + b: Unpacked, + c: Unpacked, + d: i64 +} + +fn main() { + let packed = Packed { x: 123, y: 234, z: 345 }; + + let packedInPacked = PackedInPacked { + a: 1111, + b: Packed { x: 2222, y: 3333, z: 4444 }, + c: 5555, + d: Packed { x: 6666, y: 7777, z: 8888 } + }; + + let packedInUnpacked = PackedInUnpacked { + a: -1111, + b: Packed { x: -2222, y: -3333, z: -4444 }, + c: -5555, + d: Packed { x: -6666, y: -7777, z: -8888 } + }; + + let unpackedInPacked = UnpackedInPacked { + a: 987, + b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, + c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, + d: -98 + }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/simple-tuple.rs b/src/test/debug-info/simple-tuple.rs index 84c736fab6b01..f45294221af16 100644 --- a/src/test/debug-info/simple-tuple.rs +++ b/src/test/debug-info/simple-tuple.rs @@ -35,15 +35,15 @@ fn main() { - let noPadding8 : (i8, u8) = (-100, 100); - let noPadding16 : (i16, i16, u16) = (0, 1, 2); - let noPadding32 : (i32, f32, u32) = (3, 4.5, 5); - let noPadding64 : (i64, f64, u64) = (6, 7.5, 8); + let noPadding8: (i8, u8) = (-100, 100); + let noPadding16: (i16, i16, u16) = (0, 1, 2); + let noPadding32: (i32, f32, u32) = (3, 4.5, 5); + let noPadding64: (i64, f64, u64) = (6, 7.5, 8); - let internalPadding1 : (i16, i32) = (9, 10); - let internalPadding2 : (i16, i32, u32, u64) = (11, 12, 13, 14); + let internalPadding1: (i16, i32) = (9, 10); + let internalPadding2: (i16, i32, u32, u64) = (11, 12, 13, 14); - let paddingAtEnd : (i32, i16) = (15, 16); + let paddingAtEnd: (i32, i16) = (15, 16); zzz(); } diff --git a/src/test/debug-info/struct-in-enum.rs b/src/test/debug-info/struct-in-enum.rs new file mode 100644 index 0000000000000..1002266a1a985 --- /dev/null +++ b/src/test/debug-info/struct-in-enum.rs @@ -0,0 +1,69 @@ +// 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 or the MIT license +// , 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:set print union on +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print case1 +// check:$1 = {{Case1, 0, {x = 2088533116, y = 2088533116, z = 31868}}, {Case1, 0, 8970181431921507452, 31868}} + +// debugger:print case2 +// check:$2 = {{Case2, 0, {x = 286331153, y = 286331153, z = 4369}}, {Case2, 0, 1229782938247303441, 4369}} + +// debugger:print univariant +// check:$3 = {{x = 123, y = 456, z = 789}} + +struct Struct { + x: u32, + y: i32, + z: i16 +} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum Regular { + Case1(u64, Struct), + Case2(u64, u64, i16) +} + +enum Univariant { + TheOnlyCase(Struct) +} + +fn main() { + + // In order to avoid endianess trouble all of the following test values consist of a single + // repeated byte. This way each interpretation of the union should look the same, no matter if + // this is a big or little endian machine. + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + let case1 = Case1(0, Struct { x: 2088533116, y: 2088533116, z: 31868 }); + + // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 + // 0b00010001000100010001000100010001 = 286331153 + // 0b0001000100010001 = 4369 + // 0b00010001 = 17 + let case2 = Case2(0, 1229782938247303441, 4369); + + let univariant = TheOnlyCase(Struct { x: 123, y: 456, z: 789 }); + + zzz(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/struct-style-enum.rs b/src/test/debug-info/struct-style-enum.rs new file mode 100644 index 0000000000000..61bbd2e215ff6 --- /dev/null +++ b/src/test/debug-info/struct-style-enum.rs @@ -0,0 +1,73 @@ +// 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 or the MIT license +// , 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:set print union on +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print case1 +// check:$1 = {{Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {Case1, a = 0, b = 2088533116, c = 2088533116}, {Case1, a = 0, b = 8970181431921507452}} + +// debugger:print case2 +// check:$2 = {{Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {Case2, a = 0, b = 286331153, c = 286331153}, {Case2, a = 0, b = 1229782938247303441}} + +// debugger:print case3 +// check:$3 = {{Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {Case3, a = 0, b = 1499027801, c = 1499027801}, {Case3, a = 0, b = 6438275382588823897}} + +// debugger:print univariant +// check:$4 = {a = -1} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum Regular { + Case1 { a: u64, b: u16, c: u16, d: u16, e: u16}, + Case2 { a: u64, b: u32, c: u32}, + Case3 { a: u64, b: u64 } +} + +enum Univariant { + TheOnlyCase { a: i64 } +} + +fn main() { + + // In order to avoid endianess trouble all of the following test values consist of a single + // repeated byte. This way each interpretation of the union should look the same, no matter if + // this is a big or little endian machine. + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + let case1 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }; + + // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 + // 0b00010001000100010001000100010001 = 286331153 + // 0b0001000100010001 = 4369 + // 0b00010001 = 17 + let case2 = Case2 { a: 0, b: 286331153, c: 286331153 }; + + // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897 + // 0b01011001010110010101100101011001 = 1499027801 + // 0b0101100101011001 = 22873 + // 0b01011001 = 89 + let case3 = Case3 { a: 0, b: 6438275382588823897 }; + + let univariant = TheOnlyCase { a: -1 }; + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/struct-with-destructor.rs b/src/test/debug-info/struct-with-destructor.rs index f8281bba49e9f..0719f64b2564f 100644 --- a/src/test/debug-info/struct-with-destructor.rs +++ b/src/test/debug-info/struct-with-destructor.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 // compile-flags:-Z extra-debug-info // debugger:break zzz @@ -23,18 +23,21 @@ // debugger:print withDestructor // check:$3 = {a = {x = 10, y = 20}, guard = -1} +// debugger:print nested +// check:$4 = {a = {a = {x = 7890, y = 9870}}} + struct NoDestructor { - x : i32, - y : i64 + x: i32, + y: i64 } struct WithDestructor { - x : i32, - y : i64 + x: i32, + y: i64 } impl Drop for WithDestructor { - fn finalize(&self) {} + fn drop(&self) {} } struct NoDestructorGuarded { @@ -47,6 +50,18 @@ struct WithDestructorGuarded { guard: i64 } +struct NestedInner { + a: WithDestructor +} + +impl Drop for NestedInner { + fn drop(&self) {} +} + +struct NestedOuter { + a: NestedInner +} + // The compiler adds a 'destructed' boolean field to structs implementing Drop. This field is used // at runtime to prevent drop() to be executed more than once (see middle::trans::adt). @@ -65,6 +80,8 @@ fn main() { // then the debugger will have an invalid offset for the field 'guard' and thus should not be // able to read its value correctly (dots are padding bytes, D is the boolean destructor flag): // + // 64 bit + // // NoDestructorGuarded = 0000....00000000FFFFFFFF // <--------------><------> // NoDestructor guard @@ -77,11 +94,31 @@ fn main() { // <----------------------><------> // How it actually is // WithDestructor guard // + // 32 bit + // + // NoDestructorGuarded = 000000000000FFFFFFFF + // <----------><------> + // NoDestructor guard + // + // + // withDestructorGuarded = 000000000000D...FFFFFFFF + // <----------><------> // How debug info says it is + // WithDestructor guard + // + // <--------------><------> // How it actually is + // WithDestructor guard + // let withDestructor = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }; + // expected layout (64 bit) = xxxx....yyyyyyyyD.......D... + // <--WithDestructor------> + // <-------NestedInner--------> + // <-------NestedOuter--------> + let nested = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }; + zzz(); } diff --git a/src/test/debug-info/tuple-in-tuple.rs b/src/test/debug-info/tuple-in-tuple.rs index 13f8719694e5f..9c6805dae67d3 100644 --- a/src/test/debug-info/tuple-in-tuple.rs +++ b/src/test/debug-info/tuple-in-tuple.rs @@ -34,15 +34,15 @@ // check:$7 = {{21, 22}, 23} fn main() { - let no_padding1 : ((u32, u32), u32, u32) = ((0, 1), 2, 3); - let no_padding2 : (u32, (u32, u32), u32) = (4, (5, 6), 7); - let no_padding3 : (u32, u32, (u32, u32)) = (8, 9, (10, 11)); + let no_padding1: ((u32, u32), u32, u32) = ((0, 1), 2, 3); + let no_padding2: (u32, (u32, u32), u32) = (4, (5, 6), 7); + let no_padding3: (u32, u32, (u32, u32)) = (8, 9, (10, 11)); - let internal_padding1 : (i16, (i32, i32)) = (12, (13, 14)); - let internal_padding2 : (i16, (i16, i32)) = (15, (16, 17)); + let internal_padding1: (i16, (i32, i32)) = (12, (13, 14)); + let internal_padding2: (i16, (i16, i32)) = (15, (16, 17)); - let padding_at_end1 : (i32, (i32, i16)) = (18, (19, 20)); - let padding_at_end2 : ((i32, i16), i32) = ((21, 22), 23); + let padding_at_end1: (i32, (i32, i16)) = (18, (19, 20)); + let padding_at_end2: ((i32, i16), i32) = ((21, 22), 23); zzz(); } diff --git a/src/test/debug-info/tuple-style-enum.rs b/src/test/debug-info/tuple-style-enum.rs new file mode 100644 index 0000000000000..ba1d02bb62a3c --- /dev/null +++ b/src/test/debug-info/tuple-style-enum.rs @@ -0,0 +1,73 @@ +// 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 or the MIT license +// , 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:set print union on +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print case1 +// check:$1 = {{Case1, 0, 31868, 31868, 31868, 31868}, {Case1, 0, 2088533116, 2088533116}, {Case1, 0, 8970181431921507452}} + +// debugger:print case2 +// check:$2 = {{Case2, 0, 4369, 4369, 4369, 4369}, {Case2, 0, 286331153, 286331153}, {Case2, 0, 1229782938247303441}} + +// debugger:print case3 +// check:$3 = {{Case3, 0, 22873, 22873, 22873, 22873}, {Case3, 0, 1499027801, 1499027801}, {Case3, 0, 6438275382588823897}} + +// debugger:print univariant +// check:$4 = {-1} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum Regular { + Case1(u64, u16, u16, u16, u16), + Case2(u64, u32, u32), + Case3(u64, u64) +} + +enum Univariant { + TheOnlyCase(i64) +} + +fn main() { + + // In order to avoid endianess trouble all of the following test values consist of a single + // repeated byte. This way each interpretation of the union should look the same, no matter if + // this is a big or little endian machine. + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + let case1 = Case1(0, 31868, 31868, 31868, 31868); + + // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 + // 0b00010001000100010001000100010001 = 286331153 + // 0b0001000100010001 = 4369 + // 0b00010001 = 17 + let case2 = Case2(0, 286331153, 286331153); + + // 0b0101100101011001010110010101100101011001010110010101100101011001 = 6438275382588823897 + // 0b01011001010110010101100101011001 = 1499027801 + // 0b0101100101011001 = 22873 + // 0b01011001 = 89 + let case3 = Case3(0, 6438275382588823897); + + let univariant = TheOnlyCase(-1); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/unique-enum.rs b/src/test/debug-info/unique-enum.rs new file mode 100644 index 0000000000000..443f641a85859 --- /dev/null +++ b/src/test/debug-info/unique-enum.rs @@ -0,0 +1,63 @@ +// 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 or the MIT license +// , 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 *the_a +// check:$1 = {{TheA, x = 0, y = 8970181431921507452}, {TheA, 0, 2088533116, 2088533116}} + +// debugger:print *the_b +// check:$2 = {{TheB, x = 0, y = 1229782938247303441}, {TheB, 0, 286331153, 286331153}} + +// debugger:print *univariant +// check:$3 = {123234} + +// The first element is to ensure proper alignment, irrespective of the machines word size. Since +// the size of the discriminant value is machine dependent, this has be taken into account when +// datatype layout should be predictable as in this case. +enum ABC { + TheA { x: i64, y: i64 }, + TheB (i64, i32, i32), +} + +// This is a special case since it does not have the implicit discriminant field. +enum Univariant { + TheOnlyCase(i64) +} + +fn main() { + + // In order to avoid endianess trouble all of the following test values consist of a single + // repeated byte. This way each interpretation of the union should look the same, no matter if + // this is a big or little endian machine. + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + let the_a = ~TheA { x: 0, y: 8970181431921507452 }; + + // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 + // 0b00010001000100010001000100010001 = 286331153 + // 0b0001000100010001 = 4369 + // 0b00010001 = 17 + let the_b = ~TheB (0, 286331153, 286331153); + + let univariant = ~TheOnlyCase(123234); + + zzz(); +} + +fn zzz() {()} \ No newline at end of file diff --git a/src/test/debug-info/vec-slices.rs b/src/test/debug-info/vec-slices.rs new file mode 100644 index 0000000000000..4691de0491721 --- /dev/null +++ b/src/test/debug-info/vec-slices.rs @@ -0,0 +1,72 @@ +// 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 or the MIT license +// , 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:set print pretty off +// debugger:break zzz +// debugger:run +// debugger:finish +// debugger:print empty.size_in_bytes +// check:$1 = 0 + +// debugger:print singleton.size_in_bytes +// check:$2 = 8 +// debugger:print *((int64_t[1]*)(singleton.data_ptr)) +// check:$3 = {1} + +// debugger:print multiple.size_in_bytes +// check:$4 = 32 +// debugger:print *((int64_t[4]*)(multiple.data_ptr)) +// check:$5 = {2, 3, 4, 5} + +// debugger:print slice_of_slice.size_in_bytes +// check:$6 = 16 +// debugger:print *((int64_t[2]*)(slice_of_slice.data_ptr)) +// check:$7 = {3, 4} + +// debugger:print padded_tuple.size_in_bytes +// check:$8 = 16 +// debugger:print padded_tuple.data_ptr[0] +// check:$9 = {6, 7} +// debugger:print padded_tuple.data_ptr[1] +// check:$10 = {8, 9} + +// debugger:print padded_struct.size_in_bytes +// check:$11 = 24 +// debugger:print padded_struct.data_ptr[0] +// check:$12 = {x = 10, y = 11, z = 12} +// debugger:print padded_struct.data_ptr[1] +// check:$13 = {x = 13, y = 14, z = 15} + +struct AStruct { + x: i16, + y: i32, + z: i16 +} + +fn main() { + let empty: &[i64] = &[]; + let singleton: &[i64] = &[1]; + let multiple: &[i64] = &[2, 3, 4, 5]; + let slice_of_slice = multiple.slice(1,3); + + let padded_tuple: &[(i32, i16)] = &[(6, 7), (8, 9)]; + + let padded_struct: &[AStruct] = &[ + AStruct { x: 10, y: 11, z: 12 }, + AStruct { x: 13, y: 14, z: 15 } + ]; + + zzz(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/vec.rs b/src/test/debug-info/vec.rs index f198a53729eb7..57130b45eae30 100644 --- a/src/test/debug-info/vec.rs +++ b/src/test/debug-info/vec.rs @@ -8,28 +8,20 @@ // 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 _zzz +// debugger:break zzz // debugger:run // debugger:finish // debugger:print a // check:$1 = {1, 2, 3} -// debugger:print b.vec[0] -// check:$2 = 4 -// debugger:print c->boxed.data[1] -// check:$3 = 8 -// debugger:print d->boxed.data[2] -// check:$4 = 12 fn main() { let a = [1, 2, 3]; - let b = &[4, 5, 6]; - let c = @[7, 8, 9]; - let d = ~[10, 11, 12]; - _zzz(); + + zzz(); } -fn _zzz() {()} +fn zzz() {()} diff --git a/src/test/run-pass/issue-7712.rs b/src/test/run-pass/issue-7712.rs new file mode 100644 index 0000000000000..d4faae415d202 --- /dev/null +++ b/src/test/run-pass/issue-7712.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Z debug-info + +#[allow(default_methods)]; + +pub trait TraitWithDefaultMethod { + pub fn method(self) { + () + } +} + +struct MyStruct; + +impl TraitWithDefaultMethod for MyStruct { } + +fn main() { + MyStruct.method(); +} \ No newline at end of file