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 pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
24
25 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 ),
32 LocalVariable,
33}
34
35#[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 pub dbg_var: Option<D>,
43
44 pub fragment: Option<Range<Size>>,
47
48 pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
50}
51
52pub 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 pub inlined_at: Option<L>,
69
70 pub file_start_pos: BytePos,
73 pub file_end_pos: BytePos,
74}
75
76impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
77 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 direct_offset: Size,
161 indirect_offsets: Vec<Size>,
164 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 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 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 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 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 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 if arg_index == 0 && has_proj() {
326 None
330 } else if whole_local_var.is_some() {
331 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 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 bx.set_var_name(a, &(name.clone() + ".0"));
391 bx.set_var_name(b, &(name.clone() + ".1"));
392 }
393 OperandValue::ZeroSized => {
394 }
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 let attrs = bx.tcx().codegen_instance_attrs(self.instance.def);
412 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
413 return;
414 }
415
416 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 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 LocalRef::UnsizedPlace(_) => return,
461 };
462
463 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 let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
503 && self.mir.local_kind(local) == mir::LocalKind::Arg
504 && (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 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 bx.store_to_place(place.val.llval, alloca.val);
521
522 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 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 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 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 continue;
651 } else if fragment_layout.size == var_layout.size {
652 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 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 self.debug_context = Some(FunctionDebugContext {
704 scopes: IndexVec::with_capacity(self.mir.source_scopes.len()),
705 inlined_function_scopes: Default::default(),
706 });
707
708 let variables = if self.cx.sess().opts.debuginfo == DebugInfo::Full {
710 let mut vars = DenseBitSet::new_empty(self.mir.source_scopes.len());
711 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 None
722 };
723
724 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 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 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 match discriminators.entry(callsite_span.lo()) {
806 Entry::Occupied(mut o) => {
807 *o.get_mut() += 1;
808 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}