rustc_codegen_llvm/debuginfo/
create_scope_map.rs
1use std::collections::hash_map::Entry;
2
3use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
4use rustc_codegen_ssa::traits::*;
5use rustc_data_structures::fx::FxHashMap;
6use rustc_index::Idx;
7use rustc_index::bit_set::DenseBitSet;
8use rustc_middle::mir::{Body, SourceScope};
9use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
10use rustc_middle::ty::{self, Instance};
11use rustc_session::config::DebugInfo;
12use rustc_span::{BytePos, DUMMY_SP, hygiene};
13
14use super::metadata::file_metadata;
15use super::utils::DIB;
16use crate::common::CodegenCx;
17use crate::llvm;
18use crate::llvm::debuginfo::{DILocation, DIScope};
19
20pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
23 cx: &CodegenCx<'ll, 'tcx>,
24 instance: Instance<'tcx>,
25 mir: &Body<'tcx>,
26 debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
27) {
28 let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
30 let mut vars = DenseBitSet::new_empty(mir.source_scopes.len());
31 for var_debug_info in &mir.var_debug_info {
36 vars.insert(var_debug_info.source_info.scope);
37 }
38 Some(vars)
39 } else {
40 None
42 };
43 let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
44 let mut discriminators = FxHashMap::default();
45 for idx in 0..mir.source_scopes.len() {
47 let scope = SourceScope::new(idx);
48 make_mir_scope(
49 cx,
50 instance,
51 mir,
52 &variables,
53 debug_context,
54 &mut instantiated,
55 &mut discriminators,
56 scope,
57 );
58 }
59 assert!(instantiated.count() == mir.source_scopes.len());
60}
61
62fn make_mir_scope<'ll, 'tcx>(
63 cx: &CodegenCx<'ll, 'tcx>,
64 instance: Instance<'tcx>,
65 mir: &Body<'tcx>,
66 variables: &Option<DenseBitSet<SourceScope>>,
67 debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
68 instantiated: &mut DenseBitSet<SourceScope>,
69 discriminators: &mut FxHashMap<BytePos, u32>,
70 scope: SourceScope,
71) {
72 if instantiated.contains(scope) {
73 return;
74 }
75
76 let scope_data = &mir.source_scopes[scope];
77 let parent_scope = if let Some(parent) = scope_data.parent_scope {
78 make_mir_scope(
79 cx,
80 instance,
81 mir,
82 variables,
83 debug_context,
84 instantiated,
85 discriminators,
86 parent,
87 );
88 debug_context.scopes[parent]
89 } else {
90 let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
92 debug_context.scopes[scope] = DebugScope {
93 file_start_pos: file.start_pos,
94 file_end_pos: file.end_position(),
95 ..debug_context.scopes[scope]
96 };
97 instantiated.insert(scope);
98 return;
99 };
100
101 if let Some(vars) = variables
102 && !vars.contains(scope)
103 && scope_data.inlined.is_none()
104 {
105 debug_context.scopes[scope] = parent_scope;
108 instantiated.insert(scope);
109 return;
110 }
111
112 let loc = cx.lookup_debug_loc(scope_data.span.lo());
113 let file_metadata = file_metadata(cx, &loc.file);
114
115 let dbg_scope = match scope_data.inlined {
116 Some((callee, _)) => {
117 let callee = cx.tcx.instantiate_and_normalize_erasing_regions(
120 instance.args,
121 cx.typing_env(),
122 ty::EarlyBinder::bind(callee),
123 );
124 debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| {
125 let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
126 cx.dbg_scope_fn(callee, callee_fn_abi, None)
127 })
128 }
129 None => unsafe {
130 llvm::LLVMDIBuilderCreateLexicalBlock(
131 DIB(cx),
132 parent_scope.dbg_scope,
133 file_metadata,
134 loc.line,
135 loc.col,
136 )
137 },
138 };
139
140 let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
141 let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span);
142 let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
143 let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
144
145 match discriminators.entry(callsite_span.lo()) {
164 Entry::Occupied(mut o) => {
165 *o.get_mut() += 1;
166 unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
170 .unwrap_or_else(|| {
171 cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP)
172 })
173 }
174 Entry::Vacant(v) => {
175 v.insert(0);
176 loc
177 }
178 }
179 });
180
181 debug_context.scopes[scope] = DebugScope {
182 dbg_scope,
183 inlined_at: inlined_at.or(parent_scope.inlined_at),
184 file_start_pos: loc.file.start_pos,
185 file_end_pos: loc.file.end_position(),
186 };
187 instantiated.insert(scope);
188}