Skip to main content

rustc_codegen_ssa/mir/
debuginfo.rs

1use std::collections::hash_map::Entry;
2use std::marker::PhantomData;
3use std::ops::Range;
4
5use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx};
6use rustc_data_structures::fx::FxHashMap;
7use rustc_index::IndexVec;
8use rustc_index::bit_set::DenseBitSet;
9use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
10use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
11use rustc_middle::ty::{Instance, Ty};
12use rustc_middle::{bug, mir, ty};
13use rustc_session::config::DebugInfo;
14use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, hygiene, sym};
15
16use super::operand::{OperandRef, OperandValue};
17use super::place::{PlaceRef, PlaceValue};
18use super::{FunctionCx, LocalRef, PerLocalVarDebugInfoIndexVec};
19use crate::traits::*;
20
21pub struct FunctionDebugContext<'tcx, S, L> {
22    /// Maps from source code to the corresponding debug info scope.
23    pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
24
25    /// Maps from an inlined function to its debug info declaration.
26    pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
27}
28
29#[derive(#[automatically_derived]
impl ::core::marker::Copy for VariableKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for VariableKind {
    #[inline]
    fn clone(&self) -> VariableKind {
        let _: ::core::clone::AssertParamIsClone<usize>;
        *self
    }
}Clone)]
30pub enum VariableKind {
31    ArgumentVariable(usize /*index*/),
32    LocalVariable,
33}
34
35/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
36#[derive(#[automatically_derived]
impl<'tcx, D: ::core::clone::Clone> ::core::clone::Clone for
    PerLocalVarDebugInfo<'tcx, D> {
    #[inline]
    fn clone(&self) -> PerLocalVarDebugInfo<'tcx, D> {
        PerLocalVarDebugInfo {
            name: ::core::clone::Clone::clone(&self.name),
            source_info: ::core::clone::Clone::clone(&self.source_info),
            dbg_var: ::core::clone::Clone::clone(&self.dbg_var),
            fragment: ::core::clone::Clone::clone(&self.fragment),
            projection: ::core::clone::Clone::clone(&self.projection),
        }
    }
}Clone)]
37pub struct PerLocalVarDebugInfo<'tcx, D> {
38    pub name: Symbol,
39    pub source_info: mir::SourceInfo,
40
41    /// `DIVariable` returned by `create_dbg_var`.
42    pub dbg_var: Option<D>,
43
44    /// Byte range in the `dbg_var` covered by this fragment,
45    /// if this is a fragment of a composite `VarDebugInfo`.
46    pub fragment: Option<Range<Size>>,
47
48    /// `.place.projection` from `mir::VarDebugInfo`.
49    pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
50}
51
52/// Information needed to emit a constant.
53pub struct ConstDebugInfo<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
54    pub name: String,
55    pub source_info: mir::SourceInfo,
56    pub operand: OperandRef<'tcx, Bx::Value>,
57    pub dbg_var: Bx::DIVariable,
58    pub dbg_loc: Bx::DILocation,
59    pub fragment: Option<Range<Size>>,
60    pub _phantom: PhantomData<&'a ()>,
61}
62
63#[derive(#[automatically_derived]
impl<S: ::core::clone::Clone, L: ::core::clone::Clone> ::core::clone::Clone
    for DebugScope<S, L> {
    #[inline]
    fn clone(&self) -> DebugScope<S, L> {
        DebugScope {
            dbg_scope: ::core::clone::Clone::clone(&self.dbg_scope),
            inlined_at: ::core::clone::Clone::clone(&self.inlined_at),
            file_start_pos: ::core::clone::Clone::clone(&self.file_start_pos),
            file_end_pos: ::core::clone::Clone::clone(&self.file_end_pos),
        }
    }
}Clone, #[automatically_derived]
impl<S: ::core::marker::Copy, L: ::core::marker::Copy> ::core::marker::Copy
    for DebugScope<S, L> {
}Copy, #[automatically_derived]
impl<S: ::core::fmt::Debug, L: ::core::fmt::Debug> ::core::fmt::Debug for
    DebugScope<S, L> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f, "DebugScope",
            "dbg_scope", &self.dbg_scope, "inlined_at", &self.inlined_at,
            "file_start_pos", &self.file_start_pos, "file_end_pos",
            &&self.file_end_pos)
    }
}Debug)]
64pub struct DebugScope<S, L> {
65    pub dbg_scope: S,
66
67    /// Call site location, if this scope was inlined from another function.
68    pub inlined_at: Option<L>,
69
70    // Start and end offsets of the file to which this DIScope belongs.
71    // These are used to quickly determine whether some span refers to the same file.
72    pub file_start_pos: BytePos,
73    pub file_end_pos: BytePos,
74}
75
76impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
77    /// DILocations inherit source file name from the parent DIScope. Due to macro expansions
78    /// it may so happen that the current span belongs to a different file than the DIScope
79    /// corresponding to span's containing source scope. If so, we need to create a DIScope
80    /// "extension" into that file.
81    pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>(
82        &self,
83        cx: &Cx,
84        span: Span,
85    ) -> S {
86        let pos = span.lo();
87        if pos < self.file_start_pos || pos >= self.file_end_pos {
88            let sm = cx.sess().source_map();
89            cx.extend_scope_to_file(self.dbg_scope, &sm.lookup_char_pos(pos).file)
90        } else {
91            self.dbg_scope
92        }
93    }
94}
95
96trait DebugInfoOffsetLocation<'tcx, Bx> {
97    fn deref(&self, bx: &mut Bx) -> Self;
98    fn layout(&self) -> TyAndLayout<'tcx>;
99    fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self;
100    fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self;
101    fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self;
102}
103
104impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
105    for PlaceRef<'tcx, Bx::Value>
106{
107    fn deref(&self, bx: &mut Bx) -> Self {
108        bx.load_operand(*self).deref(bx.cx())
109    }
110
111    fn layout(&self) -> TyAndLayout<'tcx> {
112        self.layout
113    }
114
115    fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self {
116        PlaceRef::project_field(*self, bx, field.index())
117    }
118
119    fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self {
120        let lloffset = bx.cx().const_usize(offset);
121        self.project_index(bx, lloffset)
122    }
123
124    fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
125        self.project_downcast(bx, variant)
126    }
127}
128
129impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
130    for TyAndLayout<'tcx>
131{
132    fn deref(&self, bx: &mut Bx) -> Self {
133        bx.cx().layout_of(
134            self.ty.builtin_deref(true).unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("cannot deref `{0}`",
        self.ty))bug!("cannot deref `{}`", self.ty)),
135        )
136    }
137
138    fn layout(&self) -> TyAndLayout<'tcx> {
139        *self
140    }
141
142    fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self {
143        self.field(bx.cx(), field.index())
144    }
145
146    fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self {
147        self.field(bx.cx(), index as usize)
148    }
149
150    fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
151        self.for_variant(bx.cx(), variant)
152    }
153}
154
155struct DebugInfoOffset<T> {
156    /// Offset from the `base` used to calculate the debuginfo offset.
157    direct_offset: Size,
158    /// Each offset in this vector indicates one level of indirection from the base or previous
159    /// indirect offset plus a dereference.
160    indirect_offsets: Vec<Size>,
161    /// The final location debuginfo should point to.
162    result: T,
163}
164
165fn calculate_debuginfo_offset<
166    'a,
167    'tcx,
168    Bx: BuilderMethods<'a, 'tcx>,
169    L: DebugInfoOffsetLocation<'tcx, Bx>,
170>(
171    bx: &mut Bx,
172    projection: &[mir::PlaceElem<'tcx>],
173    base: L,
174) -> DebugInfoOffset<L> {
175    let mut direct_offset = Size::ZERO;
176    // FIXME(eddyb) use smallvec here.
177    let mut indirect_offsets = ::alloc::vec::Vec::new()vec![];
178    let mut place = base;
179
180    for elem in projection {
181        match *elem {
182            mir::ProjectionElem::Deref => {
183                indirect_offsets.push(Size::ZERO);
184                place = place.deref(bx);
185            }
186            mir::ProjectionElem::Field(field, _) => {
187                let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
188                *offset += place.layout().fields.offset(field.index());
189                place = place.project_field(bx, field);
190            }
191            mir::ProjectionElem::Downcast(_, variant) => {
192                place = place.downcast(bx, variant);
193            }
194            mir::ProjectionElem::ConstantIndex {
195                offset: index,
196                min_length: _,
197                from_end: false,
198            } => {
199                let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
200                let FieldsShape::Array { stride, count: _ } = place.layout().fields else {
201                    ::rustc_middle::util::bug::bug_fmt(format_args!("ConstantIndex on non-array type {0:?}",
        place.layout()))bug!("ConstantIndex on non-array type {:?}", place.layout())
202                };
203                *offset += stride * index;
204                place = place.project_constant_index(bx, index);
205            }
206            _ => {
207                // Sanity check for `can_use_in_debuginfo`.
208                if !!elem.can_use_in_debuginfo() {
    ::core::panicking::panic("assertion failed: !elem.can_use_in_debuginfo()")
};assert!(!elem.can_use_in_debuginfo());
209                ::rustc_middle::util::bug::bug_fmt(format_args!("unsupported var debuginfo projection `{0:?}`",
        projection))bug!("unsupported var debuginfo projection `{:?}`", projection)
210            }
211        }
212    }
213
214    DebugInfoOffset { direct_offset, indirect_offsets, result: place }
215}
216
217impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
218    pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
219        bx.set_span(source_info.span);
220        if let Some(dbg_loc) = self.dbg_loc(source_info) {
221            bx.set_dbg_loc(dbg_loc);
222        }
223    }
224
225    fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option<Bx::DILocation> {
226        let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(source_info)?;
227        Some(self.cx.dbg_loc(dbg_scope, inlined_at, span))
228    }
229
230    fn adjusted_span_and_dbg_scope(
231        &self,
232        source_info: mir::SourceInfo,
233    ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> {
234        let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
235        let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span);
236        Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span))
237    }
238
239    fn spill_operand_to_stack(
240        operand: OperandRef<'tcx, Bx::Value>,
241        name: Option<String>,
242        bx: &mut Bx,
243    ) -> PlaceRef<'tcx, Bx::Value> {
244        // "Spill" the value onto the stack, for debuginfo,
245        // without forcing non-debuginfo uses of the local
246        // to also load from the stack every single time.
247        // FIXME(#68817) use `llvm.dbg.value` instead,
248        // at least for the cases which LLVM handles correctly.
249        let spill_slot = PlaceRef::alloca(bx, operand.layout);
250        if let Some(name) = name {
251            bx.set_var_name(spill_slot.val.llval, &(name + ".dbg.spill"));
252        }
253        operand.val.store(bx, spill_slot);
254        spill_slot
255    }
256
257    // Indicates that local is set to a new value. The `layout` and `projection` are used to
258    // calculate the offset.
259    pub(crate) fn debug_new_val_to_local(
260        &self,
261        bx: &mut Bx,
262        local: mir::Local,
263        base: PlaceRef<'tcx, Bx::Value>,
264        projection: &[mir::PlaceElem<'tcx>],
265    ) {
266        let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
267        if !full_debug_info {
268            return;
269        }
270
271        let vars = match &self.per_local_var_debug_info {
272            Some(per_local) => &per_local[local],
273            None => return,
274        };
275
276        let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
277            calculate_debuginfo_offset(bx, projection, base.layout);
278        for var in vars.iter() {
279            let Some(dbg_var) = var.dbg_var else {
280                continue;
281            };
282            let Some(dbg_loc) = self.dbg_loc(var.source_info) else {
283                continue;
284            };
285            bx.dbg_var_value(
286                dbg_var,
287                dbg_loc,
288                base.val.llval,
289                direct_offset,
290                &indirect_offsets,
291                &var.fragment,
292            );
293        }
294    }
295
296    pub(crate) fn debug_poison_to_local(&self, bx: &mut Bx, local: mir::Local) {
297        let ty = self.monomorphize(self.mir.local_decls[local].ty);
298        let layout = bx.cx().layout_of(ty);
299        let to_backend_ty = bx.cx().immediate_backend_type(layout);
300        let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout);
301        self.debug_new_val_to_local(bx, local, place_ref, &[]);
302    }
303
304    /// Apply debuginfo and/or name, after creating the `alloca` for a local,
305    /// or initializing the local with an operand (whichever applies).
306    pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
307        let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
308
309        let vars = match &self.per_local_var_debug_info {
310            Some(per_local) => &per_local[local],
311            None => return,
312        };
313        let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned();
314        let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
315
316        let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
317            let arg_index = local.index() - 1;
318
319            // Add debuginfo even to unnamed arguments.
320            // FIXME(eddyb) is this really needed?
321            if arg_index == 0 && has_proj() {
322                // Hide closure environments from debuginfo.
323                // FIXME(eddyb) shouldn't `ArgumentVariable` indices
324                // be offset to account for the hidden environment?
325                None
326            } else if whole_local_var.is_some() {
327                // No need to make up anything, there is a `mir::VarDebugInfo`
328                // covering the whole local.
329                // FIXME(eddyb) take `whole_local_var.source_info.scope` into
330                // account, just in case it doesn't use `ArgumentVariable`
331                // (after #67586 gets fixed).
332                None
333            } else {
334                let name = sym::empty;
335                let decl = &self.mir.local_decls[local];
336                let dbg_var = if full_debug_info {
337                    self.adjusted_span_and_dbg_scope(decl.source_info).map(
338                        |(dbg_scope, _, span)| {
339                            // FIXME(eddyb) is this `+ 1` needed at all?
340                            let kind = VariableKind::ArgumentVariable(arg_index + 1);
341
342                            let arg_ty = self.monomorphize(decl.ty);
343
344                            self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
345                        },
346                    )
347                } else {
348                    None
349                };
350
351                Some(PerLocalVarDebugInfo {
352                    name,
353                    source_info: decl.source_info,
354                    dbg_var,
355                    fragment: None,
356                    projection: ty::List::empty(),
357                })
358            }
359        } else {
360            None
361        };
362
363        let local_ref = &self.locals[local];
364
365        let name = if bx.sess().fewer_names() {
366            None
367        } else {
368            Some(match whole_local_var.or_else(|| fallback_var.clone()) {
369                Some(var) if var.name != sym::empty => var.name.to_string(),
370                _ => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", local))
    })format!("{local:?}"),
371            })
372        };
373
374        if let Some(name) = &name {
375            match local_ref {
376                LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => {
377                    bx.set_var_name(place.val.llval, name);
378                }
379                LocalRef::Operand(operand) => match operand.val {
380                    OperandValue::Ref(PlaceValue { llval: x, .. }) | OperandValue::Immediate(x) => {
381                        bx.set_var_name(x, name);
382                    }
383                    OperandValue::Pair(a, b) => {
384                        // FIXME(eddyb) these are scalar components,
385                        // maybe extract the high-level fields?
386                        bx.set_var_name(a, &(name.clone() + ".0"));
387                        bx.set_var_name(b, &(name.clone() + ".1"));
388                    }
389                    OperandValue::ZeroSized => {
390                        // These never have a value to talk about
391                    }
392                },
393                LocalRef::PendingOperand => {}
394            }
395        }
396
397        if !full_debug_info || vars.is_empty() && fallback_var.is_none() {
398            return;
399        }
400
401        let base = match local_ref {
402            LocalRef::PendingOperand => return,
403
404            LocalRef::Operand(operand) => {
405                // Don't spill operands onto the stack in naked functions.
406                // See: https://github.com/rust-lang/rust/issues/42779
407                let attrs = bx.tcx().codegen_instance_attrs(self.instance.def);
408                if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
409                    return;
410                }
411
412                // Don't spill `<vscale x N x i1>` for `N != 16`:
413                //
414                // SVE predicates are only one bit for each byte in an SVE vector (which makes
415                // sense, the predicate only needs to keep track of whether a lane is
416                // enabled/disabled). i.e. a `<vscale x 16 x i8>` vector has a `<vscale x 16 x i1>`
417                // predicate type. `<vscale x 16 x i1>` corresponds to two bytes of storage,
418                // multiplied by the `vscale`, with one bit for each of the sixteen lanes.
419                //
420                // For a vector with fewer elements, such as `svint32_t`/`<vscale x 4 x i32>`,
421                // while only a `<vscale x 4 x i1>` predicate type would be strictly necessary,
422                // relevant intrinsics still take a `svbool_t`/`<vscale x 16 x i1>` - this is
423                // because a `<vscale x 4 x i1>` is only half of a byte (for `vscale=1`), and with
424                // memory being byte-addressable, it's unclear how to store that.
425                //
426                // Due to this, LLVM ultimately decided not to support stores of `<vscale x N x i1>`
427                // for `N != 16`. As for `vscale=1` and `N` fewer than sixteen, partial bytes would
428                // need to be stored (except for `N=8`, but that also isn't supported). `N` can
429                // never be greater than sixteen as that ends up larger than the 128-bit increment
430                // size.
431                //
432                // Internally, with an intrinsic operating on a `svint32_t`/`<vscale x 4 x i32>`
433                // (for example), the intrinsic takes the `svbool_t`/`<vscale x 16 x i1>` predicate
434                // and casts it to a `svbool4_t`/`<vscale x 4 x i1>`. Therefore, it's important that
435                // the `<vscale x 4 x i1>` never spills because that'll cause errors during
436                // instruction selection. Spilling to the stack to create debuginfo for these
437                // intermediate values must be avoided and doing so won't affect the
438                // debugging experience anyway.
439                if operand.layout.ty.is_scalable_vector()
440                    && bx.sess().target.arch == rustc_target::spec::Arch::AArch64
441                {
442                    let (count, element_ty, _) =
443                        operand.layout.ty.scalable_vector_parts(bx.tcx()).unwrap();
444                    // i.e. `<vscale x N x i1>` when `N != 16`
445                    if element_ty.is_bool() && count != 16 {
446                        return;
447                    }
448                }
449
450                Self::spill_operand_to_stack(*operand, name, bx)
451            }
452
453            LocalRef::Place(place) => *place,
454
455            // FIXME(eddyb) add debuginfo for unsized places too.
456            LocalRef::UnsizedPlace(_) => return,
457        };
458
459        let vars = vars.iter().cloned().chain(fallback_var);
460
461        for var in vars {
462            self.debug_introduce_local_as_var(bx, local, base, var);
463        }
464    }
465
466    fn debug_introduce_local_as_var(
467        &self,
468        bx: &mut Bx,
469        local: mir::Local,
470        base: PlaceRef<'tcx, Bx::Value>,
471        var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
472    ) {
473        let Some(dbg_var) = var.dbg_var else { return };
474        let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
475
476        let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
477            calculate_debuginfo_offset(bx, var.projection, base.layout);
478
479        // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
480        // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
481        // not DWARF and LLVM doesn't support translating the resulting
482        // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView.
483        // Creating extra allocas on the stack makes the resulting debug info simple enough
484        // that LLVM can generate correct CodeView records and thus the values appear in the
485        // debugger. (#83709)
486        let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
487            && self.mir.local_kind(local) == mir::LocalKind::Arg
488            // LLVM can handle simple things but anything more complex than just a direct
489            // offset or one indirect offset of 0 is too complex for it to generate CV records
490            // correctly.
491            && (direct_offset != Size::ZERO || !#[allow(non_exhaustive_omitted_patterns)] match &indirect_offsets[..] {
    [Size::ZERO] | [] => true,
    _ => false,
}matches!(&indirect_offsets[..], [Size::ZERO] | []));
492
493        if should_create_individual_allocas {
494            let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
495                calculate_debuginfo_offset(bx, var.projection, base);
496
497            // Create a variable which will be a pointer to the actual value
498            let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty);
499            let ptr_layout = bx.layout_of(ptr_ty);
500            let alloca = PlaceRef::alloca(bx, ptr_layout);
501            bx.set_var_name(alloca.val.llval, &(var.name.to_string() + ".dbg.spill"));
502
503            // Write the pointer to the variable
504            bx.store_to_place(place.val.llval, alloca.val);
505
506            // Point the debug info to `*alloca` for the current variable
507            bx.dbg_var_addr(
508                dbg_var,
509                dbg_loc,
510                alloca.val.llval,
511                Size::ZERO,
512                &[Size::ZERO],
513                &var.fragment,
514            );
515        } else {
516            bx.dbg_var_addr(
517                dbg_var,
518                dbg_loc,
519                base.val.llval,
520                direct_offset,
521                &indirect_offsets,
522                &var.fragment,
523            );
524        }
525    }
526
527    pub(crate) fn debug_introduce_locals(
528        &self,
529        bx: &mut Bx,
530        consts: Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
531    ) {
532        if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
533            for local in self.locals.indices() {
534                self.debug_introduce_local(bx, local);
535            }
536
537            for ConstDebugInfo { name, source_info, operand, dbg_var, dbg_loc, fragment, .. } in
538                consts.into_iter()
539            {
540                self.set_debug_loc(bx, source_info);
541                let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx);
542                bx.clear_dbg_loc();
543
544                bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], &fragment);
545            }
546        }
547    }
548
549    /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
550    pub(crate) fn compute_per_local_var_debug_info(
551        &self,
552        bx: &mut Bx,
553    ) -> Option<(
554        PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>,
555        Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
556    )> {
557        let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
558
559        let target_is_msvc = self.cx.sess().target.is_like_msvc;
560
561        if !full_debug_info && self.cx.sess().fewer_names() {
562            return None;
563        }
564
565        let mut per_local = IndexVec::from_elem(::alloc::vec::Vec::new()vec![], &self.mir.local_decls);
566        let mut constants = ::alloc::vec::Vec::new()vec![];
567        let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default();
568        for var in &self.mir.var_debug_info {
569            let dbg_scope_and_span = if full_debug_info {
570                self.adjusted_span_and_dbg_scope(var.source_info)
571            } else {
572                None
573            };
574
575            let var_ty = if let Some(ref fragment) = var.composite {
576                self.monomorphize(fragment.ty)
577            } else {
578                match var.value {
579                    mir::VarDebugInfoContents::Place(place) => {
580                        self.monomorphized_place_ty(place.as_ref())
581                    }
582                    mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
583                }
584            };
585
586            let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
587                let var_kind = if let Some(arg_index) = var.argument_index
588                    && var.composite.is_none()
589                    && let mir::VarDebugInfoContents::Place(place) = var.value
590                    && place.projection.is_empty()
591                {
592                    let arg_index = arg_index as usize;
593                    if target_is_msvc {
594                        // ScalarPair parameters are spilled to the stack so they need to
595                        // be marked as a `LocalVariable` for MSVC debuggers to visualize
596                        // their data correctly. (See #81894 & #88625)
597                        let var_ty_layout = self.cx.layout_of(var_ty);
598                        if let BackendRepr::ScalarPair(_, _) = var_ty_layout.backend_repr {
599                            VariableKind::LocalVariable
600                        } else {
601                            VariableKind::ArgumentVariable(arg_index)
602                        }
603                    } else {
604                        // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
605                        // offset in closures to account for the hidden environment?
606                        VariableKind::ArgumentVariable(arg_index)
607                    }
608                } else {
609                    VariableKind::LocalVariable
610                };
611
612                if let VariableKind::ArgumentVariable(arg_index) = var_kind {
613                    match params_seen.entry((dbg_scope, arg_index)) {
614                        Entry::Occupied(o) => o.get().clone(),
615                        Entry::Vacant(v) => v
616                            .insert(
617                                self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span),
618                            )
619                            .clone(),
620                    }
621                } else {
622                    self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
623                }
624            });
625
626            let fragment = if let Some(ref fragment) = var.composite {
627                let var_layout = self.cx.layout_of(var_ty);
628
629                let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
630                    calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
631                if !indirect_offsets.is_empty() {
    ::core::panicking::panic("assertion failed: indirect_offsets.is_empty()")
};assert!(indirect_offsets.is_empty());
632
633                if fragment_layout.size == Size::ZERO {
634                    // Fragment is a ZST, so does not represent anything. Avoid generating anything
635                    // as this may conflict with a fragment that covers the entire variable.
636                    continue;
637                } else if fragment_layout.size == var_layout.size {
638                    // Fragment covers entire variable, so as far as
639                    // DWARF is concerned, it's not really a fragment.
640                    None
641                } else {
642                    Some(direct_offset..direct_offset + fragment_layout.size)
643                }
644            } else {
645                None
646            };
647
648            match var.value {
649                mir::VarDebugInfoContents::Place(place) => {
650                    per_local[place.local].push(PerLocalVarDebugInfo {
651                        name: var.name,
652                        source_info: var.source_info,
653                        dbg_var,
654                        fragment,
655                        projection: place.projection,
656                    });
657                }
658                mir::VarDebugInfoContents::Const(c) => {
659                    if let Some(dbg_var) = dbg_var {
660                        let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
661
662                        let operand = self.eval_mir_constant_to_operand(bx, &c);
663                        constants.push(ConstDebugInfo {
664                            name: var.name.to_string(),
665                            source_info: var.source_info,
666                            operand,
667                            dbg_var,
668                            dbg_loc,
669                            fragment,
670                            _phantom: PhantomData,
671                        });
672                    }
673                }
674            }
675        }
676        Some((per_local, constants))
677    }
678
679    /// Creates the function-specific debug context.
680    ///
681    /// Returns the FunctionDebugContext for the function which holds state needed
682    /// for debug info creation, if it is enabled.
683    pub(super) fn fill_function_debug_context(&mut self) {
684        if self.cx.sess().opts.debuginfo == DebugInfo::None {
685            return;
686        }
687
688        // Initialize fn debug context (including scopes).
689        self.debug_context = Some(FunctionDebugContext {
690            scopes: IndexVec::with_capacity(self.mir.source_scopes.len()),
691            inlined_function_scopes: Default::default(),
692        });
693
694        // Find all scopes with variables defined in them.
695        let variables = if self.cx.sess().opts.debuginfo == DebugInfo::Full {
696            let mut vars = DenseBitSet::new_empty(self.mir.source_scopes.len());
697            // FIXME(eddyb) take into account that arguments always have debuginfo,
698            // irrespective of their name (assuming full debuginfo is enabled).
699            // NOTE(eddyb) actually, on second thought, those are always in the
700            // function scope, which always exists.
701            for var_debug_info in &self.mir.var_debug_info {
702                vars.insert(var_debug_info.source_info.scope);
703            }
704            Some(vars)
705        } else {
706            // Nothing to emit, of course.
707            None
708        };
709
710        // Instantiate all scopes.
711        let mut discriminators = FxHashMap::default();
712        for scope in self.mir.source_scopes.indices() {
713            let scope_data = self.make_mir_scope(&variables, &mut discriminators, scope);
714            let _s = self.debug_context.as_mut().unwrap().scopes.push(scope_data);
715            if true {
    match (&_s, &scope) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    };
};debug_assert_eq!(_s, scope);
716        }
717    }
718
719    fn make_mir_scope(
720        &mut self,
721        variables: &Option<DenseBitSet<mir::SourceScope>>,
722        discriminators: &mut FxHashMap<BytePos, u32>,
723        scope: mir::SourceScope,
724    ) -> DebugScope<Bx::DIScope, Bx::DILocation> {
725        let scope_data = &self.mir.source_scopes[scope];
726        let parent_scope = if let Some(parent) = scope_data.parent_scope {
727            if true {
    if !(parent.as_u32() < scope.as_u32()) {
        ::core::panicking::panic("assertion failed: parent.as_u32() < scope.as_u32()")
    };
};debug_assert!(parent.as_u32() < scope.as_u32());
728            self.debug_context.as_ref().unwrap().scopes[parent]
729        } else {
730            // The root is the function itself.
731            let file = self.cx.sess().source_map().lookup_source_file(self.mir.span.lo());
732            let dbg_scope = self.cx.dbg_scope_fn(self.instance, self.fn_abi, Some(self.llfn));
733            return DebugScope {
734                dbg_scope,
735                inlined_at: None,
736                file_start_pos: file.start_pos,
737                file_end_pos: file.end_position(),
738            };
739        };
740
741        if let Some(vars) = variables
742            && !vars.contains(scope)
743            && scope_data.inlined.is_none()
744        {
745            // Do not create a DIScope if there are no variables defined in this
746            // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
747            return parent_scope;
748        }
749
750        let dbg_scope = match scope_data.inlined {
751            Some((callee, _)) => {
752                let callee = self.monomorphize(callee);
753                *self
754                    .debug_context
755                    .as_mut()
756                    .unwrap()
757                    .inlined_function_scopes
758                    .entry(callee)
759                    .or_insert_with(|| {
760                        let callee_fn_abi = self.cx.fn_abi_of_instance(callee, ty::List::empty());
761                        self.cx.dbg_scope_fn(callee, callee_fn_abi, None)
762                    })
763            }
764            None => self.cx.dbg_create_lexical_block(scope_data.span.lo(), parent_scope.dbg_scope),
765        };
766
767        let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
768            let callsite_span = hygiene::walk_chain_collapsed(callsite_span, self.mir.span);
769            let callsite_scope = parent_scope.adjust_dbg_scope_for_span(self.cx, callsite_span);
770            let loc = self.cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
771
772            // NB: In order to produce proper debug info for variables (particularly
773            // arguments) in multiply-inlined functions, LLVM expects to see a single
774            // DILocalVariable with multiple different DILocations in the IR. While
775            // the source information for each DILocation would be identical, their
776            // inlinedAt attributes will be unique to the particular callsite.
777            //
778            // We generate DILocations here based on the callsite's location in the
779            // source code. A single location in the source code usually can't
780            // produce multiple distinct calls so this mostly works, until
781            // macros get involved. A macro can generate multiple calls
782            // at the same span, which breaks the assumption that we're going to
783            // produce a unique DILocation for every scope we process here. We
784            // have to explicitly add discriminators if we see inlines into the
785            // same source code location.
786            //
787            // Note further that we can't key this hashtable on the span itself,
788            // because these spans could have distinct SyntaxContexts. We have
789            // to key on exactly what we're giving to LLVM.
790            match discriminators.entry(callsite_span.lo()) {
791                Entry::Occupied(mut o) => {
792                    *o.get_mut() += 1;
793                    // NB: We have to emit *something* here or we'll fail LLVM IR verification
794                    // in at least some circumstances (see issue #135322) so if the required
795                    // discriminant cannot be encoded fall back to the dummy location.
796                    self.cx.dbg_location_clone_with_discriminator(loc, *o.get()).unwrap_or_else(
797                        || self.cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP),
798                    )
799                }
800                Entry::Vacant(v) => {
801                    v.insert(0);
802                    loc
803                }
804            }
805        });
806
807        let file = self.cx.sess().source_map().lookup_source_file(scope_data.span.lo());
808        DebugScope {
809            dbg_scope,
810            inlined_at: inlined_at.or(parent_scope.inlined_at),
811            file_start_pos: file.start_pos,
812            file_end_pos: file.end_position(),
813        }
814    }
815}