@@ -44,8 +44,11 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
4444 /// if this is a fragment of a composite `VarDebugInfo`.
4545 pub fragment : Option < Range < Size > > ,
4646
47- /// `.place.projection` from `mir::VarDebugInfo`.
48- pub projection : & ' tcx ty:: List < mir:: PlaceElem < ' tcx > > ,
47+ /// `.place.direct_projection` from `mir::VarDebugInfo`.
48+ pub direct_projection : & ' tcx ty:: List < mir:: PlaceElem < ' tcx > > ,
49+
50+ /// `.place.projection_chain` from `mir::VarDebugInfo`.
51+ pub projection_chain : & ' tcx ty:: List < mir:: ProjectionFragment < ' tcx > > ,
4952}
5053
5154/// Information needed to emit a constant.
@@ -168,46 +171,68 @@ fn calculate_debuginfo_offset<
168171 L : DebugInfoOffsetLocation < ' tcx , Bx > ,
169172> (
170173 bx : & mut Bx ,
171- projection : & [ mir:: PlaceElem < ' tcx > ] ,
174+ direct_projection : & [ mir:: PlaceElem < ' tcx > ] ,
175+ projection_chain : & [ mir:: ProjectionFragment < ' tcx > ] ,
172176 base : L ,
173177) -> DebugInfoOffset < L > {
174- let mut direct_offset = Size :: ZERO ;
175- // FIXME(eddyb) use smallvec here.
176- let mut indirect_offsets = vec ! [ ] ;
177- let mut place = base;
178-
179- for elem in projection {
180- match * elem {
181- mir:: ProjectionElem :: Deref => {
182- indirect_offsets. push ( Size :: ZERO ) ;
183- place = place. deref ( bx) ;
184- }
178+ let project_direct = |bx : & mut Bx , place : L , offset, elem| {
179+ let ( new_place, new_offset) = match elem {
185180 mir:: ProjectionElem :: Field ( field, _) => {
186- let offset = indirect_offsets. last_mut ( ) . unwrap_or ( & mut direct_offset) ;
187- * offset += place. layout ( ) . fields . offset ( field. index ( ) ) ;
188- place = place. project_field ( bx, field) ;
189- }
190- mir:: ProjectionElem :: Downcast ( _, variant) => {
191- place = place. downcast ( bx, variant) ;
181+ let offset = place. layout ( ) . fields . offset ( field. index ( ) ) ;
182+ let place = place. project_field ( bx, field) ;
183+
184+ ( place, offset)
192185 }
186+ mir:: ProjectionElem :: Downcast ( _, variant) => ( place. downcast ( bx, variant) , Size :: ZERO ) ,
193187 mir:: ProjectionElem :: ConstantIndex {
194188 offset : index,
195189 min_length : _,
196190 from_end : false ,
197191 } => {
198- let offset = indirect_offsets. last_mut ( ) . unwrap_or ( & mut direct_offset) ;
199192 let FieldsShape :: Array { stride, count : _ } = place. layout ( ) . fields else {
200193 bug ! ( "ConstantIndex on non-array type {:?}" , place. layout( ) )
201194 } ;
202- * offset += stride * index;
203- place = place. project_constant_index ( bx, index) ;
195+ let offset = stride * index;
196+ let place = place. project_constant_index ( bx, index) ;
197+
198+ ( place, offset)
199+ }
200+
201+ mir:: ProjectionElem :: Deref => {
202+ // derefs handled separately
203+ bug ! (
204+ "unexpected deref in var debuginfo projection `{direct_projection:?} {projection_chain:?}`"
205+ )
204206 }
205207 _ => {
206208 // Sanity check for `can_use_in_debuginfo`.
207209 assert ! ( !elem. can_use_in_debuginfo( ) ) ;
208- bug ! ( "unsupported var debuginfo projection `{:?}`" , projection)
210+ bug ! (
211+ "unsupported var debuginfo projection `{direct_projection:?} {projection_chain:?}`"
212+ )
209213 }
210- }
214+ } ;
215+ ( new_place, offset + new_offset)
216+ } ;
217+
218+ let ( mut place, direct_offset) = direct_projection
219+ . iter ( )
220+ . fold ( ( base, Size :: ZERO ) , |( place, offset) , & elem| project_direct ( bx, place, offset, elem) ) ;
221+
222+ // FIXME(eddyb) use smallvec here.
223+ let mut indirect_offsets = vec ! [ ] ;
224+
225+ for projection in projection_chain {
226+ debug_assert_eq ! ( projection[ 0 ] , mir:: ProjectionElem :: Deref ) ;
227+ let pointee = place. deref ( bx) ;
228+
229+ let ( projected, offset) =
230+ projection[ 1 ..] . iter ( ) . fold ( ( pointee, Size :: ZERO ) , |( place, offset) , & elem| {
231+ project_direct ( bx, place, offset, elem)
232+ } ) ;
233+
234+ place = projected;
235+ indirect_offsets. push ( offset) ;
211236 }
212237
213238 DebugInfoOffset { direct_offset, indirect_offsets, result : place }
@@ -262,8 +287,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
262287 Some ( per_local) => & per_local[ local] ,
263288 None => return ,
264289 } ;
265- let whole_local_var = vars. iter ( ) . find ( |var| var. projection . is_empty ( ) ) . cloned ( ) ;
266- let has_proj = || vars. iter ( ) . any ( |var| !var. projection . is_empty ( ) ) ;
290+ let whole_local_var = vars
291+ . iter ( )
292+ . find ( |var| var. direct_projection . is_empty ( ) && var. projection_chain . is_empty ( ) )
293+ . cloned ( ) ;
294+ let has_proj = || {
295+ vars. iter ( )
296+ . any ( |var| !var. direct_projection . is_empty ( ) || !var. projection_chain . is_empty ( ) )
297+ } ;
267298
268299 let fallback_var = if self . mir . local_kind ( local) == mir:: LocalKind :: Arg {
269300 let arg_index = local. index ( ) - 1 ;
@@ -305,7 +336,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
305336 source_info : decl. source_info ,
306337 dbg_var,
307338 fragment : None ,
308- projection : ty:: List :: empty ( ) ,
339+ direct_projection : ty:: List :: empty ( ) ,
340+ projection_chain : ty:: List :: empty ( ) ,
309341 } )
310342 }
311343 } else {
@@ -388,7 +420,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
388420 let Some ( dbg_loc) = self . dbg_loc ( var. source_info ) else { return } ;
389421
390422 let DebugInfoOffset { direct_offset, indirect_offsets, result : _ } =
391- calculate_debuginfo_offset ( bx, var. projection , base. layout ) ;
423+ calculate_debuginfo_offset (
424+ bx,
425+ var. direct_projection ,
426+ var. projection_chain ,
427+ base. layout ,
428+ ) ;
392429
393430 // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
394431 // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
@@ -406,7 +443,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
406443
407444 if should_create_individual_allocas {
408445 let DebugInfoOffset { direct_offset : _, indirect_offsets : _, result : place } =
409- calculate_debuginfo_offset ( bx, var. projection , base) ;
446+ calculate_debuginfo_offset ( bx, var. direct_projection , var . projection_chain , base) ;
410447
411448 // Create a variable which will be a pointer to the actual value
412449 let ptr_ty = Ty :: new_mut_ptr ( bx. tcx ( ) , place. layout . ty ) ;
@@ -543,7 +580,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
543580 let var_layout = self . cx . layout_of ( var_ty) ;
544581
545582 let DebugInfoOffset { direct_offset, indirect_offsets, result : fragment_layout } =
546- calculate_debuginfo_offset ( bx, & fragment. projection , var_layout) ;
583+ calculate_debuginfo_offset ( bx, & fragment. projection , & [ ] , var_layout) ;
547584 assert ! ( indirect_offsets. is_empty( ) ) ;
548585
549586 if fragment_layout. size == Size :: ZERO {
@@ -562,16 +599,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
562599 } ;
563600
564601 match var. value {
565- mir:: VarDebugInfoContents :: Place ( place) => {
566- per_local[ place. local ] . push ( PerLocalVarDebugInfo {
602+ mir:: VarDebugInfoContents :: Place ( mir:: CompoundPlace {
603+ local,
604+ direct_projection,
605+ projection_chain,
606+ } ) => {
607+ per_local[ local] . push ( PerLocalVarDebugInfo {
567608 name : var. name ,
568609 source_info : var. source_info ,
569610 dbg_var,
570611 fragment,
571- // FIXME change field to be projection chain
572- projection : bx
573- . tcx ( )
574- . mk_place_elems_from_iter ( place. iter_projection_elems ( ) ) ,
612+ direct_projection,
613+ projection_chain,
575614 } ) ;
576615 }
577616 mir:: VarDebugInfoContents :: Const ( c) => {
0 commit comments