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