diff options
| author | bors <bors@rust-lang.org> | 2013-07-20 09:10:34 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-07-20 09:10:34 -0700 |
| commit | 8aae6edce09a8e2a32a154acb55c9879dbebf99c (patch) | |
| tree | d77d6659847631f404dcf08529e3b3bd0b7fa4e2 | |
| parent | 3a1db2d1e631feede472396fced1806dfd3cf677 (diff) | |
| parent | a1303cc81565a019d59be28940a94caf0f9329bf (diff) | |
| download | rust-8aae6edce09a8e2a32a154acb55c9879dbebf99c.tar.gz rust-8aae6edce09a8e2a32a154acb55c9879dbebf99c.zip | |
auto merge of #7710 : michaelwoerister/rust/WP4, r=jdm
This pull request includes various improvements: + Composite types (structs, tuples, boxes, etc) are now handled more cleanly by debuginfo generation. Most notably, field offsets are now extracted directly from LLVM types, as opposed to trying to reconstruct them. This leads to more stable handling of edge cases (e.g. packed structs or structs implementing drop). + `debuginfo.rs` in general has seen a major cleanup. This includes better formatting, more readable variable and function names, removal of dead code, and better factoring of functionality. + Handling of `VariantInfo` in `ty.rs` has been improved. That is, the `type VariantInfo = @VariantInfo_` typedef has been replaced with explicit uses of @VariantInfo, and the duplicated logic for creating VariantInfo instances in `ty::enum_variants()` and `typeck::check::mod::check_enum_variants()` has been unified into a single constructor function. Both function now look nicer too :) + Debug info generation for enum types is now mostly supported. This includes: + Good support for C-style enums. Both DWARF and `gdb` know how to handle them. + Proper description of tuple- and struct-style enum variants as unions of structs. + Proper handling of univariant enums without discriminator field. + Unfortunately `gdb` always prints all possible interpretations of a union, so debug output of enums is verbose and unintuitive. Neither `LLVM` nor `gdb` support DWARF's `DW_TAG_variant` which allows to properly describe tagged unions. Adding support for this to `LLVM` seems doable. `gdb` however is another story. In the future we might be able to use `gdb`'s Python scripting support to alleviate this problem. In agreement with @jdm this is not a high priority for now. + The debuginfo test suite has been extended with 14 test files including tests for packed structs (with Drop), boxed structs, boxed vecs, vec slices, c-style enums (standalone and embedded), empty enums, tuple- and struct-style enums, and various pointer types to the above. ~~What is not yet included is DI support for some enum edge-cases represented as described in `trans::adt::NullablePointer`.~~ Cheers, Michael PS: closes #7819, fixes #7712
43 files changed, 2728 insertions, 741 deletions
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index aeb2017c9d6..7acd9545efd 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 993649492a4..6fd0ca06474 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 a77c6c6ab52..15ffccfe70d 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -737,11 +737,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| { @@ -757,11 +757,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 821242d64c9..fd38ec39bb1 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 6741637ae9a..cd07453a60b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -670,7 +670,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(); @@ -1141,7 +1141,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) @@ -1773,7 +1773,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); } } @@ -1947,7 +1947,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| { }); @@ -2109,7 +2109,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>( } 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 00b59d187bf..0e75e4e85c2 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<DIVariable> { - debug!("create_arg"); +pub fn create_argument_metadata(bcx: block, arg: &ast::arg, span: span) -> Option<DIVariable> { + 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<DIVariable> } 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<DIType>, + 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::<ValueRef>(); - let align = sys::min_align_of::<ValueRef>(); - 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::<uint>(), - sys::min_align_of::<uint>(), 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::<libc::size_t>(), - sys::min_align_of::<libc::size_t>(), - size_t_type); - - vec_scx.add_member( - "alloc", - 0, - sys::size_of::<libc::size_t>(), - sys::min_align_of::<libc::size_t>(), - 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::<u8>(), 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::<uint>(), - sys::min_align_of::<uint>(), - 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::<int>(); - let align = sys::min_align_of::<int>(); - 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::<uint>(), sys::min_align_of::<uint>(), 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 2cd313ff431..0bf0a522a65 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 b63117d25bb..94d872aa132 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -49,6 +49,8 @@ use syntax::opt_vec; use syntax::abi::AbiSet; use syntax; +pub static INITIAL_DISCRIMINANT_VALUE: int = 0; + // Data types #[deriving(Eq, IterBytes)] @@ -275,7 +277,7 @@ struct ctxt_ { needs_unwind_cleanup_cache: @mut HashMap<t, bool>, tc_cache: @mut HashMap<uint, TypeContents>, ast_ty_to_ty_cache: @mut HashMap<node_id, ast_ty_to_ty_cache_entry>, - enum_var_cache: @mut HashMap<def_id, @~[VariantInfo]>, + enum_var_cache: @mut HashMap<def_id, @~[@VariantInfo]>, ty_param_defs: @mut HashMap<ast::node_id, TypeParameterDef>, adjustments: @mut HashMap<ast::node_id, @AutoAdjustment>, normalized_cache: @mut HashMap<t, t>, @@ -3681,8 +3683,9 @@ fn struct_ctor_id(cx: ctxt, struct_did: ast::def_id) -> Option<ast::def_id> { // 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, @@ -3690,19 +3693,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() @@ -3820,7 +3875,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 */ } @@ -3839,61 +3894,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<int> = 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") @@ -3908,7 +3933,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 4a9e0fddbe7..fa24c8c6d09 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<int> = 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 614c1723c5f..2a1f26bf441 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -565,8 +565,8 @@ extern "C" bool LLVMRustStartMultithreading() { typedef DIBuilder* DIBuilderRef; template<typename DIT> -DIT unwrapDI(LLVMValueRef ref) { - return DIT(ref ? unwrap<MDNode>(ref) : NULL); +DIT unwrapDI(LLVMValueRef ref) { + return DIT(ref ? unwrap<MDNode>(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<DIFile>(File), + unwrapDI<DIFile>(File), unwrapDI<DIArray>(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<DIScope>(Scope), Name, LinkageName, - unwrapDI<DIFile>(File), LineNo, - unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine, + unwrapDI<DIScope>(Scope), Name, LinkageName, + unwrapDI<DIFile>(File), LineNo, + unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, - unwrap<Function>(Fn), + unwrap<Function>(Fn), unwrapDI<MDNode*>(TParam), unwrapDI<MDNode*>(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<DIDescriptor>(Scope), Name, - unwrapDI<DIFile>(File), LineNumber, - SizeInBits, AlignInBits, Flags, - unwrapDI<DIType>(DerivedFrom), - unwrapDI<DIArray>(Elements), RunTimeLang, + unwrapDI<DIDescriptor>(Scope), Name, + unwrapDI<DIFile>(File), LineNumber, + SizeInBits, AlignInBits, Flags, + unwrapDI<DIType>(DerivedFrom), + unwrapDI<DIArray>(Elements), RunTimeLang, unwrapDI<MDNode*>(VTableHolder))); } @@ -692,12 +692,12 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( unsigned Flags, LLVMValueRef Ty) { return wrap(Builder->createMemberType( - unwrapDI<DIDescriptor>(Scope), Name, + unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNo, - SizeInBits, AlignInBits, OffsetInBits, Flags, + SizeInBits, AlignInBits, OffsetInBits, Flags, unwrapDI<DIType>(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<DIDescriptor>(Scope), + unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(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<DIDescriptor>(Scope), Name, - unwrapDI<DIFile>(File), - LineNo, + return wrap(Builder->createLocalVariable(Tag, + unwrapDI<DIDescriptor>(Scope), Name, + unwrapDI<DIFile>(File), + LineNo, unwrapDI<DIType>(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<DIType>(Ty), + unwrapDI<DIType>(Ty), unwrapDI<DIArray>(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<DIType>(Ty), + unwrapDI<DIType>(Ty), unwrapDI<DIArray>(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<Value*>(reinterpret_cast<Value**>(Ptr), Count))); @@ -770,8 +770,8 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMValueRef VarInfo, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI<DIVariable>(VarInfo), + unwrap(Val), + unwrapDI<DIVariable>(VarInfo), unwrap(InsertAtEnd))); } @@ -781,7 +781,61 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMValueRef VarInfo, LLVMValueRef InsertBefore) { return wrap(Builder->insertDeclare( - unwrap(Val), - unwrapDI<DIVariable>(VarInfo), + unwrap(Val), + unwrapDI<DIVariable>(VarInfo), unwrap<Instruction>(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<DIDescriptor>(Scope), + Name, + unwrapDI<DIFile>(File), + LineNumber, + SizeInBits, + AlignInBits, + unwrapDI<DIArray>(Elements), + unwrapDI<DIType>(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<DIDescriptor>(Scope), + Name, + unwrapDI<DIFile>(File), + LineNumber, + SizeInBits, + AlignInBits, + Flags, + unwrapDI<DIArray>(Elements), + RunTimeLang)); +} \ No newline at end of file diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index d5f03ac604b..5b6c3ed2f52 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 index dfd0fbf8655..7610301f6f0 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 00000000000..70c85258c79 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *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 00000000000..38aa9c38810 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *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 index e3951c94b6f..9087bb36fa5 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 index f00872c00b0..8b6eca3e37f 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 index 86d02185bda..da199941c84 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 index ce5b50459f6..52f5a2cba1e 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 4a3a65a9055..c63cffd7b74 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 00000000000..86162f0fa04 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *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 00000000000..8abead65196 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print 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 00000000000..47e433ea814 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print 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 00000000000..d7cce4e6f3f --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print 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 bf53d95b588..207899fe3b5 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 00000000000..7e42690548e --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 f5563cda259..225dfedfec7 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 00000000000..1a3600a7d8c --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print 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 00000000000..e42631599a9 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print 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 00000000000..3eb1c2ef01e --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 00000000000..d3afd4b11f9 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print first +// check:$1 = {<No data fields>} + +// debugger:print second +// check:$2 = {<No data fields>} + +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 "{<No data fields>}" 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 00000000000..6d3b157d63e --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print 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 00000000000..9ff91aa00d1 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 00000000000..859166cb023 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 84c736fab6b..f45294221af 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 00000000000..1002266a1a9 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 00000000000..61bbd2e215f --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 f8281bba49e..0719f64b256 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 13f8719694e..9c6805dae67 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 00000000000..ba1d02bb62a --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 00000000000..443f641a858 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print *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 00000000000..4691de04917 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249 + +// compile-flags:-Z extra-debug-info +// debugger: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 f198a53729e..57130b45eae 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 00000000000..d4faae415d2 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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 |
