1
+ use std::collections::hash_map::Entry;
2
+
1
3
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
2
4
use rustc_codegen_ssa::traits::*;
5
+ use rustc_data_structures::fx::FxHashMap;
3
6
use rustc_index::Idx;
4
7
use rustc_index::bit_set::BitSet;
5
8
use rustc_middle::mir::{Body, SourceScope};
6
9
use rustc_middle::ty::layout::FnAbiOf;
7
10
use rustc_middle::ty::{self, Instance};
8
11
use rustc_session::config::DebugInfo;
12
+ use rustc_span::BytePos;
9
13
10
14
use super::metadata::file_metadata;
11
15
use super::utils::DIB;
@@ -37,10 +41,20 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
37
41
None
38
42
};
39
43
let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
44
+ let mut discriminators = FxHashMap::default();
40
45
// Instantiate all scopes.
41
46
for idx in 0..mir.source_scopes.len() {
42
47
let scope = SourceScope::new(idx);
43
- make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
48
+ make_mir_scope(
49
+ cx,
50
+ instance,
51
+ mir,
52
+ &variables,
53
+ debug_context,
54
+ &mut instantiated,
55
+ &mut discriminators,
56
+ scope,
57
+ );
44
58
}
45
59
assert!(instantiated.count() == mir.source_scopes.len());
46
60
}
@@ -52,6 +66,7 @@ fn make_mir_scope<'ll, 'tcx>(
52
66
variables: &Option<BitSet<SourceScope>>,
53
67
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
54
68
instantiated: &mut BitSet<SourceScope>,
69
+ discriminators: &mut FxHashMap<BytePos, u32>,
55
70
scope: SourceScope,
56
71
) {
57
72
if instantiated.contains(scope) {
@@ -60,7 +75,16 @@ fn make_mir_scope<'ll, 'tcx>(
60
75
61
76
let scope_data = &mir.source_scopes[scope];
62
77
let parent_scope = if let Some(parent) = scope_data.parent_scope {
63
- make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent);
78
+ make_mir_scope(
79
+ cx,
80
+ instance,
81
+ mir,
82
+ variables,
83
+ debug_context,
84
+ instantiated,
85
+ discriminators,
86
+ parent,
87
+ );
64
88
debug_context.scopes[parent]
65
89
} else {
66
90
// The root is the function itself.
@@ -117,7 +141,37 @@ fn make_mir_scope<'ll, 'tcx>(
117
141
// FIXME(eddyb) this doesn't account for the macro-related
118
142
// `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
119
143
let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
120
- cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
144
+ let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
145
+
146
+ // NB: In order to produce proper debug info for variables (particularly
147
+ // arguments) in multiply-inline functions, LLVM expects to see a single
148
+ // DILocalVariable with multiple different DILocations in the IR. While
149
+ // the source information for each DILocation would be identical, their
150
+ // inlinedAt attributes will be unique to the particular callsite.
151
+ //
152
+ // We generate DILocations here based on the callsite's location in the
153
+ // source code. A single location in the source code usually can't
154
+ // produce multiple distinct calls so this mostly works, until
155
+ // proc-macros get involved. A proc-macro can generate multiple calls
156
+ // at the same span, which breaks the assumption that we're going to
157
+ // produce a unique DILocation for every scope we process here. We
158
+ // have to explicitly add discriminators if we see inlines into the
159
+ // same source code location.
160
+ //
161
+ // Note further that we can't key this hashtable on the span itself,
162
+ // because these spans could have distinct SyntaxContexts. We have
163
+ // to key on exactly what we're giving to LLVM.
164
+ match discriminators.entry(callsite_span.lo()) {
165
+ Entry::Occupied(mut o) => {
166
+ *o.get_mut() += 1;
167
+ unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
168
+ .expect("Failed to encode discriminator in DILocation")
169
+ }
170
+ Entry::Vacant(v) => {
171
+ v.insert(0);
172
+ loc
173
+ }
174
+ }
121
175
});
122
176
123
177
debug_context.scopes[scope] = DebugScope {
0 commit comments