]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/debuginfo/create_scope_map.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librustc_trans / debuginfo / create_scope_map.rs
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.
4 //
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.
10
11 use super::FunctionDebugContext;
12 use super::metadata::file_metadata;
13 use super::utils::{DIB, span_start};
14
15 use llvm;
16 use llvm::debuginfo::{DIScope, DISubprogram};
17 use common::{CrateContext, FunctionContext};
18 use rustc::mir::{Mir, VisibilityScope};
19
20 use libc::c_uint;
21 use std::ptr;
22
23 use syntax_pos::Pos;
24
25 use rustc_data_structures::bitvec::BitVector;
26 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
27
28 use syntax_pos::BytePos;
29
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,
37 }
38
39 impl MirDebugScope {
40 pub fn is_valid(&self) -> bool {
41 !self.scope_metadata.is_null()
42 }
43 }
44
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) -> IndexVec<VisibilityScope, MirDebugScope> {
48 let mir = fcx.mir();
49 let null_scope = MirDebugScope {
50 scope_metadata: ptr::null_mut(),
51 file_start_pos: BytePos(0),
52 file_end_pos: BytePos(0)
53 };
54 let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
55
56 let fn_metadata = match fcx.debug_context {
57 FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
58 FunctionDebugContext::DebugInfoDisabled |
59 FunctionDebugContext::FunctionWithoutDebugInfo => {
60 return scopes;
61 }
62 };
63
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());
69 }
70
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);
75 }
76
77 scopes
78 }
79
80 fn make_mir_scope(ccx: &CrateContext,
81 mir: &Mir,
82 has_variables: &BitVector,
83 fn_metadata: DISubprogram,
84 scope: VisibilityScope,
85 scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
86 if scopes[scope].is_valid() {
87 return;
88 }
89
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);
93 scopes[parent]
94 } else {
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,
101 };
102 return;
103 };
104
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.
108
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;
114 return;
115 }
116 }
117
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(
122 DIB(ccx),
123 parent_scope.scope_metadata,
124 file_metadata,
125 loc.line as c_uint,
126 loc.col.to_usize() as c_uint)
127 };
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,
132 };
133 }