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