From c19f493129e45e1f23aaf67900d092fcc2a81ff3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 29 Aug 2013 11:44:11 +0200 Subject: [PATCH] debuginfo: Added test cases for structs, tuples, enums, etc passed by value. Also updated documentation comments in debuginfo and renamed DebugContext to CrateDebugContext. --- src/librustc/middle/trans/context.rs | 4 +- src/librustc/middle/trans/debuginfo.rs | 49 +++++---- src/rustllvm/rustllvm.def.in | 3 + .../by-value-non-immediate-argument.rs | 99 +++++++++++++++++++ .../debug-info/by-value-struct-argument.rs | 34 ------- .../var-captured-in-managed-closure.rs | 2 - .../var-captured-in-nested-closure.rs | 74 ++++++++++++++ .../var-captured-in-sendable-closure.rs | 2 - .../var-captured-in-stack-closure.rs | 2 - 9 files changed, 206 insertions(+), 63 deletions(-) create mode 100644 src/test/debug-info/by-value-non-immediate-argument.rs delete mode 100644 src/test/debug-info/by-value-struct-argument.rs create mode 100644 src/test/debug-info/var-captured-in-nested-closure.rs diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index e7781e93d8c..59159f61f48 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -111,7 +111,7 @@ pub struct CrateContext { // decl_gc_metadata knows whether to link to the module metadata, which // is not emitted by LLVM's GC pass when no functions use GC. uses_gc: bool, - dbg_cx: Option, + dbg_cx: Option, do_not_commit_warning_issued: bool } @@ -161,7 +161,7 @@ pub fn new(sess: session::Session, let crate_map = decl_crate_map(sess, link_meta, llmod); let dbg_cx = if sess.opts.debuginfo { - Some(debuginfo::DebugContext::new(llmod, name.to_owned())) + Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned())) } else { None }; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 70eb54313ca..1a39e0aa1a0 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -27,7 +27,7 @@ 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::local_var_metadata(bcx: block, local: &ast::local)`. +functions like `debuginfo::create_local_var_metadata(bcx: block, local: &ast::local)`. 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 @@ -37,9 +37,8 @@ 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. - +All private state used by the module is stored within either the CrateDebugContext struct (owned by +the CrateContext) or the FunctionDebugContext (owned by the FunctionContext). This file consists of three conceptual sections: 1. The public interface of the module @@ -92,7 +91,7 @@ //=------------------------------------------------------------------------------------------------- /// A context object for maintaining all state needed by the debuginfo module. -pub struct DebugContext { +pub struct CrateDebugContext { priv crate_file: ~str, priv llcontext: ContextRef, priv builder: DIBuilderRef, @@ -101,13 +100,13 @@ pub struct DebugContext { priv created_types: HashMap, } -impl DebugContext { - pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext { - debug!("DebugContext::new"); +impl CrateDebugContext { + pub fn new(llmod: ModuleRef, crate: ~str) -> CrateDebugContext { + debug!("CrateDebugContext::new"); let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) }; // DIBuilder inherits context from the module, so we'd better use the same one let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; - return DebugContext { + return CrateDebugContext { crate_file: crate, llcontext: llcontext, builder: builder, @@ -165,9 +164,9 @@ struct FunctionDebugContextData { } enum VariableAccess { - // The value given is a pointer to data + // The value given is a pointer to the data (T*) DirectVariable, - // The value given has to be dereferenced once to get the pointer to data + // The value given has to be dereferenced once to get the pointer to data (T**) IndirectVariable } @@ -224,9 +223,9 @@ pub fn create_local_var_metadata(bcx: @mut Block, } } -/// Creates debug information for a local variable introduced in the head of a match-statement arm. +/// Creates debug information for a variable captured in a closure. /// -// /// Adds the created metadata nodes directly to the crate's IR. +/// Adds the created metadata nodes directly to the crate's IR. pub fn create_captured_var_metadata(bcx: @mut Block, node_id: ast::NodeId, llptr: ValueRef, @@ -321,7 +320,8 @@ pub fn create_self_argument_metadata(bcx: @mut Block, _) => { explicit_self.span } - _ => bcx.ccx().sess.bug(fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem)) + _ => bcx.ccx().sess.bug( + fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem)) }; let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata; @@ -361,14 +361,10 @@ pub fn create_argument_metadata(bcx: @mut Block, let fcx = bcx.fcx; let cx = fcx.ccx; - let pattern = arg.pat; - let filename = span_start(cx, pattern.span).file.name; - let def_map = cx.tcx.def_map; - let file_metadata = file_metadata(cx, filename); let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata; - do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| { + do pat_util::pat_bindings(def_map, arg.pat) |_, node_id, span, path_ref| { let llptr = match bcx.fcx.llargs.find_copy(&node_id) { Some(v) => v, @@ -429,13 +425,24 @@ pub fn set_source_location(fcx: &FunctionContext, } } +/// Enables emitting source locations for the given functions. +/// +/// Since we don't want source locations to be emitted for the function prelude, they are disabled +/// when beginning to translate a new function. This functions switches source location emitting on +/// and must therefore be called before the first real statement/expression of the function is +/// translated. pub fn start_emitting_source_locations(fcx: &mut FunctionContext) { match fcx.debug_context { FunctionDebugContext(~ref mut data) => data.source_locations_enabled = true, - _ => { /* safe to ignore */} + _ => { /* safe to ignore */ } } } +/// Creates the function-specific debug context. +/// +/// Returns the FunctionDebugContext for the function which holds state needed for debug info +/// creation. The function may also return another variant of the FunctionDebugContext enum which +/// indicates why no debuginfo should be created for the function. pub fn create_function_debug_context(cx: &mut CrateContext, fn_ast_id: ast::NodeId, param_substs: Option<@param_substs>, @@ -1663,7 +1670,7 @@ fn bytes_to_bits(bytes: uint) -> c_ulonglong { } #[inline] -fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { +fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext { cx.dbg_cx.get_mut_ref() } diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index e2cec6a04f3..79cfe8b2851 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -608,6 +608,9 @@ LLVMDIBuilderCreateEnumerator LLVMDIBuilderCreateEnumerationType LLVMDIBuilderCreateUnionType LLVMDIBuilderCreateTemplateTypeParameter +LLVMDIBuilderCreateOpDeref +LLVMDIBuilderCreateOpPlus +LLVMDIBuilderCreateComplexVariable LLVMSetUnnamedAddr LLVMRustAddPass LLVMRustAddAnalysisPasses diff --git a/src/test/debug-info/by-value-non-immediate-argument.rs b/src/test/debug-info/by-value-non-immediate-argument.rs new file mode 100644 index 00000000000..da9c79a00ed --- /dev/null +++ b/src/test/debug-info/by-value-non-immediate-argument.rs @@ -0,0 +1,99 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run + +// debugger:finish +// debugger:print s +// check:$1 = {a = 1, b = 2.5} +// debugger:continue + +// debugger:finish +// debugger:print x +// check:$2 = {a = 3, b = 4.5} +// debugger:print y +// check:$3 = 5 +// debugger:print z +// check:$4 = 6.5 +// debugger:continue + +// debugger:finish +// debugger:print a +// check:$5 = {7, 8, 9.5, 10.5} +// debugger:continue + +// debugger:finish +// debugger:print a +// check:$6 = {11.5, 12.5, 13, 14} +// debugger:continue + +// debugger:finish +// debugger:print x +// check:$7 = {{Case1, x = 0, y = 8970181431921507452}, {Case1, 0, 2088533116, 2088533116}} +// debugger:continue + +#[deriving(Clone)] +struct Struct { + a: int, + b: float +} + +#[deriving(Clone)] +struct StructStruct { + a: Struct, + b: Struct +} + +fn fun(s: Struct) { + zzz(); +} + +fn fun_fun(StructStruct { a: x, b: Struct { a: y, b: z } }: StructStruct) { + zzz(); +} + +fn tup(a: (int, uint, float, float)) { + zzz(); +} + +struct Newtype(float, float, int, uint); + +fn new_type(a: Newtype) { + zzz(); +} + +// 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 Enum { + Case1 { x: i64, y: i64 }, + Case2 (i64, i32, i32), +} + +fn by_val_enum(x: Enum) { + zzz(); +} + +fn main() { + fun(Struct { a: 1, b: 2.5 }); + fun_fun(StructStruct { a: Struct { a: 3, b: 4.5 }, b: Struct { a: 5, b: 6.5 } }); + tup((7, 8, 9.5, 10.5)); + new_type(Newtype(11.5, 12.5, 13, 14)); + + // 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452 + // 0b01111100011111000111110001111100 = 2088533116 + // 0b0111110001111100 = 31868 + // 0b01111100 = 124 + by_val_enum(Case1 { x: 0, y: 8970181431921507452 }); +} + +fn zzz() {()} diff --git a/src/test/debug-info/by-value-struct-argument.rs b/src/test/debug-info/by-value-struct-argument.rs deleted file mode 100644 index 73bd805a6f4..00000000000 --- a/src/test/debug-info/by-value-struct-argument.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags:-Z extra-debug-info -// debugger:break zzz -// debugger:run - -// debugger:finish -// debugger:print s -// check:$1 = {a = 1, b = 2.5} -// debugger:continue - -#[deriving(Clone)] -struct Struct { - a: int, - b: float -} - -fn fun(s: Struct) { - zzz(); -} - -fn main() { - fun(Struct { a: 1, b: 2.5 }); -} - -fn zzz() {()} diff --git a/src/test/debug-info/var-captured-in-managed-closure.rs b/src/test/debug-info/var-captured-in-managed-closure.rs index 37f5fef471b..002bfbd2242 100644 --- a/src/test/debug-info/var-captured-in-managed-closure.rs +++ b/src/test/debug-info/var-captured-in-managed-closure.rs @@ -8,8 +8,6 @@ // 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 diff --git a/src/test/debug-info/var-captured-in-nested-closure.rs b/src/test/debug-info/var-captured-in-nested-closure.rs new file mode 100644 index 00000000000..60ad2a3544a --- /dev/null +++ b/src/test/debug-info/var-captured-in-nested-closure.rs @@ -0,0 +1,74 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Z extra-debug-info +// debugger:break zzz +// debugger:run +// debugger:finish + +// debugger:print variable +// check:$1 = 1 +// debugger:print constant +// check:$2 = 2 +// debugger:print a_struct +// check:$3 = {a = -3, b = 4.5, c = 5} +// debugger:print *struct_ref +// check:$4 = {a = -3, b = 4.5, c = 5} +// debugger:print *owned +// check:$5 = 6 +// debugger:print managed->val +// check:$6 = 7 +// debugger:print closure_local +// check:$7 = 8 +// debugger:continue + +#[allow(unused_variable)]; + +struct Struct { + a: int, + b: float, + c: uint +} + +fn main() { + let mut variable = 1; + let constant = 2; + + let a_struct = Struct { + a: -3, + b: 4.5, + c: 5 + }; + + let struct_ref = &a_struct; + let owned = ~6; + let managed = @7; + + let closure = || { + let closure_local = 8; + + let nested_closure = || { + zzz(); + variable = constant + a_struct.a + struct_ref.a + *owned + *managed + closure_local; + }; + + // breaking here will yield a wrong value for 'constant'. In particular, GDB will + // read the value of the register that supposedly contains the pointer to 'constant' + // and try derefence it. The register, however, already contains the actual value, and + // not a pointer to it. -mw + // zzz(); + + nested_closure(); + }; + + closure(); +} + +fn zzz() {()} diff --git a/src/test/debug-info/var-captured-in-sendable-closure.rs b/src/test/debug-info/var-captured-in-sendable-closure.rs index c4568bd592f..01839ea7835 100644 --- a/src/test/debug-info/var-captured-in-sendable-closure.rs +++ b/src/test/debug-info/var-captured-in-sendable-closure.rs @@ -8,8 +8,6 @@ // 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 diff --git a/src/test/debug-info/var-captured-in-stack-closure.rs b/src/test/debug-info/var-captured-in-stack-closure.rs index 6694d5111a8..3ce7d6fd89b 100644 --- a/src/test/debug-info/var-captured-in-stack-closure.rs +++ b/src/test/debug-info/var-captured-in-stack-closure.rs @@ -8,8 +8,6 @@ // 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 -- GitLab