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