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, FunctionDebugContextData};
12 use super::metadata::file_metadata;
13 use super::utils::{DIB, span_start};
16 use llvm::debuginfo::DIScope;
17 use common::CodegenCx;
18 use rustc::mir::{Mir, SourceScope};
24 use rustc_data_structures::bitvec::BitArray;
25 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
27 use syntax_pos::BytePos;
29 #[derive(Clone, Copy, Debug)]
30 pub struct MirDebugScope<'ll> {
31 pub scope_metadata: Option<&'ll DIScope>,
32 // Start and end offsets of the file to which this DIScope belongs.
33 // These are used to quickly determine whether some span refers to the same file.
34 pub file_start_pos: BytePos,
35 pub file_end_pos: BytePos,
38 impl MirDebugScope<'ll> {
39 pub fn is_valid(&self) -> bool {
40 !self.scope_metadata.is_none()
44 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
45 /// If debuginfo is disabled, the returned vector is empty.
46 pub fn create_mir_scopes(
47 cx: &CodegenCx<'ll, '_>,
49 debug_context: &FunctionDebugContext<'ll>,
50 ) -> IndexVec<SourceScope, MirDebugScope<'ll>> {
51 let null_scope = MirDebugScope {
53 file_start_pos: BytePos(0),
54 file_end_pos: BytePos(0)
56 let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes);
58 let debug_context = match *debug_context {
59 FunctionDebugContext::RegularContext(ref data) => data,
60 FunctionDebugContext::DebugInfoDisabled |
61 FunctionDebugContext::FunctionWithoutDebugInfo => {
66 // Find all the scopes with variables defined in them.
67 let mut has_variables = BitArray::new(mir.source_scopes.len());
68 for var in mir.vars_iter() {
69 let decl = &mir.local_decls[var];
70 has_variables.insert(decl.visibility_scope);
73 // Instantiate all scopes.
74 for idx in 0..mir.source_scopes.len() {
75 let scope = SourceScope::new(idx);
76 make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes);
82 fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
84 has_variables: &BitArray<SourceScope>,
85 debug_context: &FunctionDebugContextData<'ll>,
87 scopes: &mut IndexVec<SourceScope, MirDebugScope<'ll>>) {
88 if scopes[scope].is_valid() {
92 let scope_data = &mir.source_scopes[scope];
93 let parent_scope = if let Some(parent) = scope_data.parent_scope {
94 make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes);
97 // The root is the function itself.
98 let loc = span_start(cx, mir.span);
99 scopes[scope] = MirDebugScope {
100 scope_metadata: Some(debug_context.fn_metadata),
101 file_start_pos: loc.file.start_pos,
102 file_end_pos: loc.file.end_pos,
107 if !has_variables.contains(scope) {
108 // Do not create a DIScope if there are no variables
109 // defined in this MIR Scope, to avoid debuginfo bloat.
111 // However, we don't skip creating a nested scope if
112 // our parent is the root, because we might want to
113 // put arguments in the root and not have shadowing.
114 if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata {
115 scopes[scope] = parent_scope;
120 let loc = span_start(cx, scope_data.span);
121 let file_metadata = file_metadata(cx,
123 debug_context.defining_crate);
125 let scope_metadata = unsafe {
126 Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
128 parent_scope.scope_metadata.unwrap(),
131 loc.col.to_usize() as c_uint))
133 scopes[scope] = MirDebugScope {
135 file_start_pos: loc.file.start_pos,
136 file_end_pos: loc.file.end_pos,