1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use super::FunctionDebugContext;
12 use super::metadata::file_metadata;
13 use super::utils::{DIB, span_start};
16 use llvm::debuginfo::{DIScope, DISubprogram};
17 use common::{CrateContext, FunctionContext};
18 use rustc::mir::{Mir, VisibilityScope};
25 use rustc_data_structures::bitvec::BitVector;
26 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
28 use syntax_pos::BytePos;
30 #[derive(Clone, Copy, Debug)]
31 pub struct MirDebugScope {
32 pub scope_metadata: DIScope,
33 // Start and end offsets of the file to which this DIScope belongs.
34 // These are used to quickly determine whether some span refers to the same file.
35 pub file_start_pos: BytePos,
36 pub file_end_pos: BytePos,
40 pub fn is_valid(&self) -> bool {
41 !self.scope_metadata.is_null()
45 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
46 /// If debuginfo is disabled, the returned vector is empty.
47 pub fn create_mir_scopes(fcx: &FunctionContext, mir: &Mir, debug_context: &FunctionDebugContext)
48 -> IndexVec<VisibilityScope, MirDebugScope> {
49 let null_scope = MirDebugScope {
50 scope_metadata: ptr::null_mut(),
51 file_start_pos: BytePos(0),
52 file_end_pos: BytePos(0)
54 let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
56 let fn_metadata = match *debug_context {
57 FunctionDebugContext::RegularContext(ref data) => data.fn_metadata,
58 FunctionDebugContext::DebugInfoDisabled |
59 FunctionDebugContext::FunctionWithoutDebugInfo => {
64 // Find all the scopes with variables defined in them.
65 let mut has_variables = BitVector::new(mir.visibility_scopes.len());
66 for var in mir.vars_iter() {
67 let decl = &mir.local_decls[var];
68 has_variables.insert(decl.source_info.unwrap().scope.index());
71 // Instantiate all scopes.
72 for idx in 0..mir.visibility_scopes.len() {
73 let scope = VisibilityScope::new(idx);
74 make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
80 fn make_mir_scope(ccx: &CrateContext,
82 has_variables: &BitVector,
83 fn_metadata: DISubprogram,
84 scope: VisibilityScope,
85 scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
86 if scopes[scope].is_valid() {
90 let scope_data = &mir.visibility_scopes[scope];
91 let parent_scope = if let Some(parent) = scope_data.parent_scope {
92 make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
95 // The root is the function itself.
96 let loc = span_start(ccx, mir.span);
97 scopes[scope] = MirDebugScope {
98 scope_metadata: fn_metadata,
99 file_start_pos: loc.file.start_pos,
100 file_end_pos: loc.file.end_pos,
105 if !has_variables.contains(scope.index()) {
106 // Do not create a DIScope if there are no variables
107 // defined in this MIR Scope, to avoid debuginfo bloat.
109 // However, we don't skip creating a nested scope if
110 // our parent is the root, because we might want to
111 // put arguments in the root and not have shadowing.
112 if parent_scope.scope_metadata != fn_metadata {
113 scopes[scope] = parent_scope;
118 let loc = span_start(ccx, scope_data.span);
119 let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
120 let scope_metadata = unsafe {
121 llvm::LLVMRustDIBuilderCreateLexicalBlock(
123 parent_scope.scope_metadata,
126 loc.col.to_usize() as c_uint)
128 scopes[scope] = MirDebugScope {
129 scope_metadata: scope_metadata,
130 file_start_pos: loc.file.start_pos,
131 file_end_pos: loc.file.end_pos,