]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_codegen_ssa / src / mir / debuginfo.rs
CommitLineData
dfeec247 1use crate::traits::*;
49aad941 2use rustc_index::IndexVec;
3dfed10e 3use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
ba9703b0
XL
4use rustc_middle::mir;
5use rustc_middle::ty;
9c376795 6use rustc_middle::ty::layout::TyAndLayout;
f2b60f7d 7use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
ba9703b0 8use rustc_session::config::DebugInfo;
74b04a01 9use rustc_span::symbol::{kw, Symbol};
dfeec247 10use rustc_span::{BytePos, Span};
49aad941 11use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx};
e74abb32 12
fc512014 13use super::operand::{OperandRef, OperandValue};
74b04a01 14use super::place::PlaceRef;
dfeec247 15use super::{FunctionCx, LocalRef};
e74abb32 16
487cf647
FG
17use std::ops::Range;
18
29967ef6
XL
19pub struct FunctionDebugContext<S, L> {
20 pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
e74abb32
XL
21}
22
23#[derive(Copy, Clone)]
24pub enum VariableKind {
25 ArgumentVariable(usize /*index*/),
26 LocalVariable,
27}
28
74b04a01 29/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
487cf647 30#[derive(Clone)]
74b04a01
XL
31pub struct PerLocalVarDebugInfo<'tcx, D> {
32 pub name: Symbol,
33 pub source_info: mir::SourceInfo,
34
35 /// `DIVariable` returned by `create_dbg_var`.
36 pub dbg_var: Option<D>,
37
487cf647
FG
38 /// Byte range in the `dbg_var` covered by this fragment,
39 /// if this is a fragment of a composite `VarDebugInfo`.
40 pub fragment: Option<Range<Size>>,
41
74b04a01
XL
42 /// `.place.projection` from `mir::VarDebugInfo`.
43 pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
49aad941
FG
44
45 /// `references` from `mir::VarDebugInfo`.
46 pub references: u8,
74b04a01
XL
47}
48
e74abb32 49#[derive(Clone, Copy, Debug)]
29967ef6 50pub struct DebugScope<S, L> {
04454e1e 51 pub dbg_scope: S,
29967ef6
XL
52
53 /// Call site location, if this scope was inlined from another function.
54 pub inlined_at: Option<L>,
55
e74abb32
XL
56 // Start and end offsets of the file to which this DIScope belongs.
57 // These are used to quickly determine whether some span refers to the same file.
58 pub file_start_pos: BytePos,
59 pub file_end_pos: BytePos,
60}
61
29967ef6 62impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
9c376795 63 /// DILocations inherit source file name from the parent DIScope. Due to macro expansions
29967ef6 64 /// it may so happen that the current span belongs to a different file than the DIScope
9c376795 65 /// corresponding to span's containing source scope. If so, we need to create a DIScope
29967ef6
XL
66 /// "extension" into that file.
67 pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>(
68 &self,
69 cx: &Cx,
70 span: Span,
71 ) -> S {
29967ef6
XL
72 let pos = span.lo();
73 if pos < self.file_start_pos || pos >= self.file_end_pos {
74 let sm = cx.sess().source_map();
04454e1e 75 cx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file)
29967ef6 76 } else {
04454e1e 77 self.dbg_scope
29967ef6 78 }
e74abb32
XL
79 }
80}
81
9c376795
FG
82trait DebugInfoOffsetLocation<'tcx, Bx> {
83 fn deref(&self, bx: &mut Bx) -> Self;
84 fn layout(&self) -> TyAndLayout<'tcx>;
353b0b11 85 fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self;
49aad941 86 fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self;
9c376795
FG
87 fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self;
88}
89
90impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
91 for PlaceRef<'tcx, Bx::Value>
92{
93 fn deref(&self, bx: &mut Bx) -> Self {
94 bx.load_operand(*self).deref(bx.cx())
95 }
96
97 fn layout(&self) -> TyAndLayout<'tcx> {
98 self.layout
99 }
100
353b0b11 101 fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self {
9c376795
FG
102 PlaceRef::project_field(*self, bx, field.index())
103 }
104
49aad941
FG
105 fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self {
106 let lloffset = bx.cx().const_usize(offset);
107 self.project_index(bx, lloffset)
108 }
109
9c376795
FG
110 fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
111 self.project_downcast(bx, variant)
112 }
113}
114
115impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
116 for TyAndLayout<'tcx>
117{
118 fn deref(&self, bx: &mut Bx) -> Self {
119 bx.cx().layout_of(
120 self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty,
121 )
122 }
123
124 fn layout(&self) -> TyAndLayout<'tcx> {
125 *self
126 }
127
353b0b11 128 fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self {
9c376795
FG
129 self.field(bx.cx(), field.index())
130 }
131
49aad941
FG
132 fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self {
133 self.field(bx.cx(), index as usize)
134 }
135
9c376795
FG
136 fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
137 self.for_variant(bx.cx(), variant)
138 }
139}
140
141struct DebugInfoOffset<T> {
142 /// Offset from the `base` used to calculate the debuginfo offset.
143 direct_offset: Size,
144 /// Each offset in this vector indicates one level of indirection from the base or previous
145 /// indirect offset plus a dereference.
146 indirect_offsets: Vec<Size>,
147 /// The final location debuginfo should point to.
148 result: T,
149}
150
151fn calculate_debuginfo_offset<
152 'a,
153 'tcx,
154 Bx: BuilderMethods<'a, 'tcx>,
155 L: DebugInfoOffsetLocation<'tcx, Bx>,
156>(
157 bx: &mut Bx,
158 local: mir::Local,
159 var: &PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
160 base: L,
161) -> DebugInfoOffset<L> {
162 let mut direct_offset = Size::ZERO;
163 // FIXME(eddyb) use smallvec here.
164 let mut indirect_offsets = vec![];
165 let mut place = base;
166
167 for elem in &var.projection[..] {
168 match *elem {
169 mir::ProjectionElem::Deref => {
170 indirect_offsets.push(Size::ZERO);
171 place = place.deref(bx);
172 }
173 mir::ProjectionElem::Field(field, _) => {
174 let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
175 *offset += place.layout().fields.offset(field.index());
176 place = place.project_field(bx, field);
177 }
178 mir::ProjectionElem::Downcast(_, variant) => {
179 place = place.downcast(bx, variant);
180 }
49aad941
FG
181 mir::ProjectionElem::ConstantIndex {
182 offset: index,
183 min_length: _,
184 from_end: false,
185 } => {
186 let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
187 let FieldsShape::Array { stride, count: _ } = place.layout().fields else {
188 span_bug!(var.source_info.span, "ConstantIndex on non-array type {:?}", place.layout())
189 };
190 *offset += stride * index;
191 place = place.project_constant_index(bx, index);
192 }
353b0b11
FG
193 _ => {
194 // Sanity check for `can_use_in_debuginfo`.
195 debug_assert!(!elem.can_use_in_debuginfo());
196 span_bug!(
197 var.source_info.span,
198 "unsupported var debuginfo place `{:?}`",
199 mir::Place { local, projection: var.projection },
200 )
201 }
9c376795
FG
202 }
203 }
204
205 DebugInfoOffset { direct_offset, indirect_offsets, result: place }
206}
207
e74abb32 208impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
74b04a01 209 pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
29967ef6
XL
210 bx.set_span(source_info.span);
211 if let Some(dbg_loc) = self.dbg_loc(source_info) {
212 bx.set_dbg_loc(dbg_loc);
e74abb32
XL
213 }
214 }
215
29967ef6
XL
216 fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option<Bx::DILocation> {
217 let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(source_info)?;
218 Some(self.cx.dbg_loc(dbg_scope, inlined_at, span))
219 }
220
221 fn adjusted_span_and_dbg_scope(
222 &self,
223 source_info: mir::SourceInfo,
224 ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
225 let span = self.adjust_span_for_debugging(source_info.span);
226 let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
227 Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span))
228 }
229
230 /// In order to have a good line stepping behavior in debugger, we overwrite debug
f2b60f7d
FG
231 /// locations of macro expansions with that of the outermost expansion site (when the macro is
232 /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
29967ef6 233 fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
e74abb32 234 // Bail out if debug info emission is not enabled.
29967ef6
XL
235 if self.debug_context.is_none() {
236 return span;
e74abb32
XL
237 }
238
f2b60f7d 239 if self.cx.tcx().should_collapse_debuginfo(span) {
e74abb32
XL
240 // Walk up the macro expansion chain until we reach a non-expanded span.
241 // We also stop at the function body level because no line stepping can occur
242 // at the level above that.
e74abb32 243 // Use span of the outermost expansion site, while keeping the original lexical scope.
29967ef6 244 span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt());
e74abb32 245 }
e74abb32 246
29967ef6 247 span
e74abb32
XL
248 }
249
fc512014
XL
250 fn spill_operand_to_stack(
251 operand: &OperandRef<'tcx, Bx::Value>,
252 name: Option<String>,
253 bx: &mut Bx,
254 ) -> PlaceRef<'tcx, Bx::Value> {
255 // "Spill" the value onto the stack, for debuginfo,
256 // without forcing non-debuginfo uses of the local
257 // to also load from the stack every single time.
258 // FIXME(#68817) use `llvm.dbg.value` instead,
259 // at least for the cases which LLVM handles correctly.
260 let spill_slot = PlaceRef::alloca(bx, operand.layout);
261 if let Some(name) = name {
262 bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
263 }
264 operand.val.store(bx, spill_slot);
265 spill_slot
266 }
267
e74abb32
XL
268 /// Apply debuginfo and/or name, after creating the `alloca` for a local,
269 /// or initializing the local with an operand (whichever applies).
e74abb32 270 pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
74b04a01
XL
271 let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
272
e74abb32
XL
273 let vars = match &self.per_local_var_debug_info {
274 Some(per_local) => &per_local[local],
275 None => return,
276 };
487cf647 277 let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned();
74b04a01 278 let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
e74abb32 279
74b04a01 280 let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
e74abb32
XL
281 let arg_index = local.index() - 1;
282
283 // Add debuginfo even to unnamed arguments.
284 // FIXME(eddyb) is this really needed?
74b04a01 285 if arg_index == 0 && has_proj() {
e74abb32
XL
286 // Hide closure environments from debuginfo.
287 // FIXME(eddyb) shouldn't `ArgumentVariable` indices
288 // be offset to account for the hidden environment?
289 None
74b04a01
XL
290 } else if whole_local_var.is_some() {
291 // No need to make up anything, there is a `mir::VarDebugInfo`
292 // covering the whole local.
293 // FIXME(eddyb) take `whole_local_var.source_info.scope` into
294 // account, just in case it doesn't use `ArgumentVariable`
295 // (after #67586 gets fixed).
296 None
e74abb32 297 } else {
5869c6ff 298 let name = kw::Empty;
74b04a01 299 let decl = &self.mir.local_decls[local];
29967ef6
XL
300 let dbg_var = if full_debug_info {
301 self.adjusted_span_and_dbg_scope(decl.source_info).map(
302 |(dbg_scope, _, span)| {
303 // FIXME(eddyb) is this `+ 1` needed at all?
304 let kind = VariableKind::ArgumentVariable(arg_index + 1);
305
fc512014 306 let arg_ty = self.monomorphize(decl.ty);
29967ef6
XL
307
308 self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
309 },
310 )
74b04a01 311 } else {
29967ef6 312 None
74b04a01 313 };
74b04a01
XL
314
315 Some(PerLocalVarDebugInfo {
316 name,
317 source_info: decl.source_info,
318 dbg_var,
487cf647 319 fragment: None,
74b04a01 320 projection: ty::List::empty(),
49aad941 321 references: 0,
e74abb32 322 })
74b04a01 323 }
e74abb32 324 } else {
74b04a01 325 None
e74abb32
XL
326 };
327
328 let local_ref = &self.locals[local];
329
353b0b11
FG
330 // FIXME Should the return place be named?
331 let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE {
74b04a01
XL
332 None
333 } else {
487cf647 334 Some(match whole_local_var.or(fallback_var.clone()) {
5869c6ff 335 Some(var) if var.name != kw::Empty => var.name.to_string(),
e74abb32 336 _ => format!("{:?}", local),
74b04a01
XL
337 })
338 };
339
340 if let Some(name) = &name {
e74abb32 341 match local_ref {
dfeec247 342 LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => {
74b04a01 343 bx.set_var_name(place.llval, name);
e74abb32 344 }
353b0b11 345 LocalRef::Operand(operand) => match operand.val {
dfeec247 346 OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => {
74b04a01 347 bx.set_var_name(x, name);
e74abb32
XL
348 }
349 OperandValue::Pair(a, b) => {
350 // FIXME(eddyb) these are scalar components,
351 // maybe extract the high-level fields?
352 bx.set_var_name(a, &(name.clone() + ".0"));
74b04a01 353 bx.set_var_name(b, &(name.clone() + ".1"));
e74abb32 354 }
dfeec247 355 },
353b0b11 356 LocalRef::PendingOperand => {}
e74abb32
XL
357 }
358 }
359
74b04a01 360 if !full_debug_info || vars.is_empty() && fallback_var.is_none() {
e74abb32
XL
361 return;
362 }
363
e74abb32 364 let base = match local_ref {
353b0b11 365 LocalRef::PendingOperand => return,
74b04a01 366
353b0b11 367 LocalRef::Operand(operand) => {
3dfed10e
XL
368 // Don't spill operands onto the stack in naked functions.
369 // See: https://github.com/rust-lang/rust/issues/42779
370 let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
371 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
372 return;
373 }
374
fc512014 375 Self::spill_operand_to_stack(operand, name, bx)
74b04a01
XL
376 }
377
378 LocalRef::Place(place) => *place,
379
380 // FIXME(eddyb) add debuginfo for unsized places too.
381 LocalRef::UnsizedPlace(_) => return,
e74abb32
XL
382 };
383
487cf647 384 let vars = vars.iter().cloned().chain(fallback_var);
e74abb32
XL
385
386 for var in vars {
49aad941
FG
387 self.debug_introduce_local_as_var(bx, local, base, var);
388 }
389 }
390
391 fn debug_introduce_local_as_var(
392 &self,
393 bx: &mut Bx,
394 local: mir::Local,
395 mut base: PlaceRef<'tcx, Bx::Value>,
396 var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
397 ) {
398 let Some(dbg_var) = var.dbg_var else { return };
399 let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
400
401 let DebugInfoOffset { mut direct_offset, indirect_offsets, result: _ } =
402 calculate_debuginfo_offset(bx, local, &var, base.layout);
403 let mut indirect_offsets = &indirect_offsets[..];
404
405 // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
406 // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
407 // not DWARF and LLVM doesn't support translating the resulting
408 // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView.
409 // Creating extra allocas on the stack makes the resulting debug info simple enough
410 // that LLVM can generate correct CodeView records and thus the values appear in the
411 // debugger. (#83709)
412 let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
413 && self.mir.local_kind(local) == mir::LocalKind::Arg
414 // LLVM can handle simple things but anything more complex than just a direct
415 // offset or one indirect offset of 0 is too complex for it to generate CV records
416 // correctly.
417 && (direct_offset != Size::ZERO || !matches!(indirect_offsets, [Size::ZERO] | []));
418
419 let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| {
420 // Create a variable which will be a pointer to the actual value
421 let ptr_ty = bx
422 .tcx()
423 .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty });
424 let ptr_layout = bx.layout_of(ptr_ty);
425 let alloca = PlaceRef::alloca(bx, ptr_layout);
426 bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount));
427
428 // Write the pointer to the variable
429 bx.store(place.llval, alloca.llval, alloca.align);
430
431 // Point the debug info to `*alloca` for the current variable
432 alloca
433 };
434
435 if var.references > 0 {
436 base = calculate_debuginfo_offset(bx, local, &var, base).result;
437
438 // Point the debug info to `&...&base == alloca` for the current variable
439 for refcount in 0..var.references {
440 base = create_alloca(bx, base, refcount);
cdc7bbd5 441 }
49aad941
FG
442
443 direct_offset = Size::ZERO;
444 indirect_offsets = &[];
445 } else if should_create_individual_allocas {
446 let place = calculate_debuginfo_offset(bx, local, &var, base).result;
447
448 // Point the debug info to `*alloca` for the current variable
449 base = create_alloca(bx, place, 0);
450 direct_offset = Size::ZERO;
451 indirect_offsets = &[Size::ZERO];
e74abb32 452 }
49aad941
FG
453
454 bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, indirect_offsets, None);
e74abb32
XL
455 }
456
457 pub fn debug_introduce_locals(&self, bx: &mut Bx) {
458 if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
459 for local in self.locals.indices() {
460 self.debug_introduce_local(bx, local);
461 }
462 }
463 }
e74abb32 464
74b04a01
XL
465 /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
466 pub fn compute_per_local_var_debug_info(
467 &self,
fc512014 468 bx: &mut Bx,
74b04a01
XL
469 ) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
470 let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
471
6a06907d
XL
472 let target_is_msvc = self.cx.sess().target.is_like_msvc;
473
74b04a01
XL
474 if !full_debug_info && self.cx.sess().fewer_names() {
475 return None;
476 }
477
478 let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
479 for var in &self.mir.var_debug_info {
29967ef6
XL
480 let dbg_scope_and_span = if full_debug_info {
481 self.adjusted_span_and_dbg_scope(var.source_info)
74b04a01 482 } else {
29967ef6 483 None
74b04a01 484 };
fc512014 485
29967ef6 486 let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
49aad941 487 let (mut var_ty, var_kind) = match var.value {
fc512014
XL
488 mir::VarDebugInfoContents::Place(place) => {
489 let var_ty = self.monomorphized_place_ty(place.as_ref());
353b0b11 490 let var_kind = if let Some(arg_index) = var.argument_index
fc512014 491 && place.projection.is_empty()
fc512014 492 {
353b0b11 493 let arg_index = arg_index as usize;
6a06907d 494 if target_is_msvc {
c295e0f8
XL
495 // ScalarPair parameters are spilled to the stack so they need to
496 // be marked as a `LocalVariable` for MSVC debuggers to visualize
497 // their data correctly. (See #81894 & #88625)
498 let var_ty_layout = self.cx.layout_of(var_ty);
499 if let Abi::ScalarPair(_, _) = var_ty_layout.abi {
500 VariableKind::LocalVariable
501 } else {
353b0b11 502 VariableKind::ArgumentVariable(arg_index)
6a06907d
XL
503 }
504 } else {
505 // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
506 // offset in closures to account for the hidden environment?
353b0b11 507 VariableKind::ArgumentVariable(arg_index)
6a06907d 508 }
fc512014
XL
509 } else {
510 VariableKind::LocalVariable
511 };
512 (var_ty, var_kind)
513 }
514 mir::VarDebugInfoContents::Const(c) => {
6a06907d 515 let ty = self.monomorphize(c.ty());
fc512014
XL
516 (ty, VariableKind::LocalVariable)
517 }
487cf647
FG
518 mir::VarDebugInfoContents::Composite { ty, fragments: _ } => {
519 let ty = self.monomorphize(ty);
520 (ty, VariableKind::LocalVariable)
521 }
74b04a01 522 };
fc512014 523
49aad941
FG
524 for _ in 0..var.references {
525 var_ty =
526 bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty });
527 }
528
29967ef6 529 self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
74b04a01
XL
530 });
531
fc512014
XL
532 match var.value {
533 mir::VarDebugInfoContents::Place(place) => {
534 per_local[place.local].push(PerLocalVarDebugInfo {
535 name: var.name,
536 source_info: var.source_info,
537 dbg_var,
487cf647 538 fragment: None,
fc512014 539 projection: place.projection,
49aad941 540 references: var.references,
fc512014
XL
541 });
542 }
543 mir::VarDebugInfoContents::Const(c) => {
544 if let Some(dbg_var) = dbg_var {
5e7ed085 545 let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
fc512014
XL
546
547 if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
49aad941 548 self.set_debug_loc(bx, var.source_info);
fc512014
XL
549 let base = Self::spill_operand_to_stack(
550 &operand,
551 Some(var.name.to_string()),
552 bx,
553 );
554
487cf647 555 bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None);
fc512014
XL
556 }
557 }
558 }
487cf647
FG
559 mir::VarDebugInfoContents::Composite { ty, ref fragments } => {
560 let var_ty = self.monomorphize(ty);
561 let var_layout = self.cx.layout_of(var_ty);
562 for fragment in fragments {
563 let mut fragment_start = Size::ZERO;
564 let mut fragment_layout = var_layout;
565
566 for elem in &fragment.projection {
567 match *elem {
568 mir::ProjectionElem::Field(field, _) => {
569 let i = field.index();
570 fragment_start += fragment_layout.fields.offset(i);
571 fragment_layout = fragment_layout.field(self.cx, i);
572 }
573 _ => span_bug!(
574 var.source_info.span,
575 "unsupported fragment projection `{:?}`",
576 elem,
577 ),
578 }
579 }
580
581 let place = fragment.contents;
582 per_local[place.local].push(PerLocalVarDebugInfo {
583 name: var.name,
584 source_info: var.source_info,
585 dbg_var,
586 fragment: if fragment_layout.size == var_layout.size {
587 // Fragment covers entire variable, so as far as
588 // DWARF is concerned, it's not really a fragment.
589 None
590 } else {
591 Some(fragment_start..fragment_start + fragment_layout.size)
592 },
593 projection: place.projection,
49aad941 594 references: var.references,
487cf647
FG
595 });
596 }
597 }
fc512014 598 }
e74abb32 599 }
e74abb32 600 Some(per_local)
e74abb32
XL
601 }
602}