11use crate :: traits:: * ;
22use rustc:: mir;
33use rustc:: session:: config:: DebugInfo ;
4+ use rustc:: ty;
45use rustc:: ty:: layout:: { LayoutOf , Size } ;
5- use rustc:: ty:: TyCtxt ;
66use rustc_hir:: def_id:: CrateNum ;
77use rustc_index:: vec:: IndexVec ;
88
9- use rustc_span:: symbol:: kw ;
9+ use rustc_span:: symbol:: { kw , Symbol } ;
1010use rustc_span:: { BytePos , Span } ;
1111
1212use super :: OperandValue ;
@@ -24,6 +24,19 @@ pub enum VariableKind {
2424 LocalVariable ,
2525}
2626
27+ /// Like `mir::VarDebugInfo`, but within a `mir::Local`.
28+ #[ derive( Copy , Clone ) ]
29+ pub struct PerLocalVarDebugInfo < ' tcx , D > {
30+ pub name : Symbol ,
31+ pub source_info : mir:: SourceInfo ,
32+
33+ /// `DIVariable` returned by `create_dbg_var`.
34+ pub dbg_var : Option < D > ,
35+
36+ /// `.place.projection` from `mir::VarDebugInfo`.
37+ pub projection : & ' tcx ty:: List < mir:: PlaceElem < ' tcx > > ,
38+ }
39+
2740#[ derive( Clone , Copy , Debug ) ]
2841pub struct DebugScope < D > {
2942 pub scope_metadata : Option < D > ,
@@ -103,6 +116,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
103116 // FIXME(eddyb) use `llvm.dbg.value` (which would work for operands),
104117 // not just `llvm.dbg.declare` (which requires `alloca`).
105118 pub fn debug_introduce_local ( & self , bx : & mut Bx , local : mir:: Local ) {
119+ let full_debug_info = bx. sess ( ) . opts . debuginfo == DebugInfo :: Full ;
120+
106121 // FIXME(eddyb) maybe name the return place as `_0` or `return`?
107122 if local == mir:: RETURN_PLACE {
108123 return ;
@@ -112,35 +127,63 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
112127 Some ( per_local) => & per_local[ local] ,
113128 None => return ,
114129 } ;
115- let whole_local_var = vars. iter ( ) . copied ( ) . find ( |var| var. place . projection . is_empty ( ) ) ;
116- let has_proj = || vars. iter ( ) . any ( |var| !var. place . projection . is_empty ( ) ) ;
130+ let whole_local_var = vars. iter ( ) . find ( |var| var. projection . is_empty ( ) ) . copied ( ) ;
131+ let has_proj = || vars. iter ( ) . any ( |var| !var. projection . is_empty ( ) ) ;
117132
118- let ( fallback_var, kind ) = if self . mir . local_kind ( local) == mir:: LocalKind :: Arg {
133+ let fallback_var = if self . mir . local_kind ( local) == mir:: LocalKind :: Arg {
119134 let arg_index = local. index ( ) - 1 ;
120135
121136 // Add debuginfo even to unnamed arguments.
122137 // FIXME(eddyb) is this really needed?
123- let var = if arg_index == 0 && has_proj ( ) {
138+ if arg_index == 0 && has_proj ( ) {
124139 // Hide closure environments from debuginfo.
125140 // FIXME(eddyb) shouldn't `ArgumentVariable` indices
126141 // be offset to account for the hidden environment?
127142 None
143+ } else if whole_local_var. is_some ( ) {
144+ // No need to make up anything, there is a `mir::VarDebugInfo`
145+ // covering the whole local.
146+ // FIXME(eddyb) take `whole_local_var.source_info.scope` into
147+ // account, just in case it doesn't use `ArgumentVariable`
148+ // (after #67586 gets fixed).
149+ None
128150 } else {
129- Some ( mir:: VarDebugInfo {
130- name : kw:: Invalid ,
131- source_info : self . mir . local_decls [ local] . source_info ,
132- place : local. into ( ) ,
151+ let name = kw:: Invalid ;
152+ let decl = & self . mir . local_decls [ local] ;
153+ let ( scope, span) = if full_debug_info {
154+ self . debug_loc ( decl. source_info )
155+ } else {
156+ ( None , decl. source_info . span )
157+ } ;
158+ let dbg_var = scope. map ( |scope| {
159+ // FIXME(eddyb) is this `+ 1` needed at all?
160+ let kind = VariableKind :: ArgumentVariable ( arg_index + 1 ) ;
161+
162+ self . cx . create_dbg_var (
163+ self . debug_context . as_ref ( ) . unwrap ( ) ,
164+ name,
165+ self . monomorphize ( & decl. ty ) ,
166+ scope,
167+ kind,
168+ span,
169+ )
170+ } ) ;
171+
172+ Some ( PerLocalVarDebugInfo {
173+ name,
174+ source_info : decl. source_info ,
175+ dbg_var,
176+ projection : ty:: List :: empty ( ) ,
133177 } )
134- } ;
135- ( var, VariableKind :: ArgumentVariable ( arg_index + 1 ) )
178+ }
136179 } else {
137- ( None , VariableKind :: LocalVariable )
180+ None
138181 } ;
139182
140183 let local_ref = & self . locals [ local] ;
141184
142185 if !bx. sess ( ) . fewer_names ( ) {
143- let name = match whole_local_var. or ( fallback_var. as_ref ( ) ) {
186+ let name = match whole_local_var. or ( fallback_var) {
144187 Some ( var) if var. name != kw:: Invalid => var. name . to_string ( ) ,
145188 _ => format ! ( "{:?}" , local) ,
146189 } ;
@@ -163,7 +206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
163206 }
164207 }
165208
166- if bx . sess ( ) . opts . debuginfo != DebugInfo :: Full {
209+ if !full_debug_info {
167210 return ;
168211 }
169212
@@ -178,22 +221,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
178221 _ => return ,
179222 } ;
180223
181- let vars = vars. iter ( ) . copied ( ) . chain ( if whole_local_var. is_none ( ) {
182- fallback_var. as_ref ( )
183- } else {
184- None
185- } ) ;
224+ let vars = vars. iter ( ) . copied ( ) . chain ( fallback_var) ;
186225
187226 for var in vars {
188227 let mut layout = base. layout ;
189228 let mut direct_offset = Size :: ZERO ;
190229 // FIXME(eddyb) use smallvec here.
191230 let mut indirect_offsets = vec ! [ ] ;
192231
193- let kind =
194- if var. place . projection . is_empty ( ) { kind } else { VariableKind :: LocalVariable } ;
195-
196- for elem in & var. place . projection [ ..] {
232+ for elem in & var. projection [ ..] {
197233 match * elem {
198234 mir:: ProjectionElem :: Deref => {
199235 indirect_offsets. push ( Size :: ZERO ) ;
@@ -202,7 +238,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
202238 . ty
203239 . builtin_deref ( true )
204240 . unwrap_or_else ( || {
205- span_bug ! ( var. source_info. span, "cannot deref `{}`" , layout. ty, )
241+ span_bug ! ( var. source_info. span, "cannot deref `{}`" , layout. ty)
206242 } )
207243 . ty ,
208244 ) ;
@@ -219,24 +255,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
219255 _ => span_bug ! (
220256 var. source_info. span,
221257 "unsupported var debuginfo place `{:?}`" ,
222- var. place ,
258+ mir :: Place { local , projection : var. projection } ,
223259 ) ,
224260 }
225261 }
226262
227263 let ( scope, span) = self . debug_loc ( var. source_info ) ;
228264 if let Some ( scope) = scope {
229- let dbg_var =
230- bx. create_dbg_var ( debug_context , var . name , layout . ty , scope , kind , span ) ;
231- bx . dbg_var_addr (
232- debug_context ,
233- dbg_var ,
234- scope ,
235- base . llval ,
236- direct_offset ,
237- & indirect_offsets ,
238- span ,
239- ) ;
265+ if let Some ( dbg_var) = var . dbg_var {
266+ bx. dbg_var_addr (
267+ debug_context ,
268+ dbg_var ,
269+ scope ,
270+ base . llval ,
271+ direct_offset ,
272+ & indirect_offsets ,
273+ span ,
274+ ) ;
275+ }
240276 }
241277 }
242278 }
@@ -248,20 +284,60 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
248284 }
249285 }
250286 }
251- }
252287
253- /// Partition all `VarDebuginfo` in `body`, by their base `Local`.
254- pub fn per_local_var_debug_info (
255- tcx : TyCtxt < ' tcx > ,
256- body : & ' a mir:: Body < ' tcx > ,
257- ) -> Option < IndexVec < mir:: Local , Vec < & ' a mir:: VarDebugInfo < ' tcx > > > > {
258- if tcx. sess . opts . debuginfo == DebugInfo :: Full || !tcx. sess . fewer_names ( ) {
259- let mut per_local = IndexVec :: from_elem ( vec ! [ ] , & body. local_decls ) ;
260- for var in & body. var_debug_info {
261- per_local[ var. place . local ] . push ( var) ;
288+ /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
289+ pub fn compute_per_local_var_debug_info (
290+ & self ,
291+ ) -> Option < IndexVec < mir:: Local , Vec < PerLocalVarDebugInfo < ' tcx , Bx :: DIVariable > > > > {
292+ let full_debug_info = self . cx . sess ( ) . opts . debuginfo == DebugInfo :: Full ;
293+
294+ if !( full_debug_info || !self . cx . sess ( ) . fewer_names ( ) ) {
295+ return None ;
296+ }
297+
298+ let mut per_local = IndexVec :: from_elem ( vec ! [ ] , & self . mir . local_decls ) ;
299+ for var in & self . mir . var_debug_info {
300+ let ( scope, span) = if full_debug_info {
301+ self . debug_loc ( var. source_info )
302+ } else {
303+ ( None , var. source_info . span )
304+ } ;
305+ let dbg_var = scope. map ( |scope| {
306+ let place = var. place ;
307+ let var_ty = self . monomorphized_place_ty ( place. as_ref ( ) ) ;
308+ let var_kind = if self . mir . local_kind ( place. local ) == mir:: LocalKind :: Arg
309+ && place. projection . is_empty ( )
310+ {
311+ // FIXME(eddyb, #67586) take `var.source_info.scope` into
312+ // account to avoid using `ArgumentVariable` more than once
313+ // per argument local.
314+
315+ let arg_index = place. local . index ( ) - 1 ;
316+
317+ // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
318+ // offset in closures to account for the hidden environment?
319+ // Also, is this `+ 1` needed at all?
320+ VariableKind :: ArgumentVariable ( arg_index + 1 )
321+ } else {
322+ VariableKind :: LocalVariable
323+ } ;
324+ self . cx . create_dbg_var (
325+ self . debug_context . as_ref ( ) . unwrap ( ) ,
326+ var. name ,
327+ var_ty,
328+ scope,
329+ var_kind,
330+ span,
331+ )
332+ } ) ;
333+
334+ per_local[ var. place . local ] . push ( PerLocalVarDebugInfo {
335+ name : var. name ,
336+ source_info : var. source_info ,
337+ dbg_var,
338+ projection : var. place . projection ,
339+ } ) ;
262340 }
263341 Some ( per_local)
264- } else {
265- None
266342 }
267343}
0 commit comments