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<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 direct_offset: Size,
158 indirect_offsets: Vec<Size>,
161 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 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 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 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 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 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 if arg_index == 0 && has_proj() {
322 None
326 } else if whole_local_var.is_some() {
327 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 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 bx.set_var_name(a, &(name.clone() + ".0"));
387 bx.set_var_name(b, &(name.clone() + ".1"));
388 }
389 OperandValue::ZeroSized => {
390 }
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 let attrs = bx.tcx().codegen_instance_attrs(self.instance.def);
408 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
409 return;
410 }
411
412 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 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 LocalRef::UnsizedPlace(_) => return,
457 };
458
459 if base.layout.peel_transparent_wrappers(bx).ty.is_scalable_vector()
465 && bx.tcx().backend_optimization_level(()) == OptLevel::No
466 && bx.sess().opts.debuginfo != DebugInfo::None
467 {
468 return;
469 }
470
471 let vars = vars.iter().cloned().chain(fallback_var);
472
473 for var in vars {
474 self.debug_introduce_local_as_var(bx, local, base, var);
475 }
476 }
477
478 fn debug_introduce_local_as_var(
479 &self,
480 bx: &mut Bx,
481 local: mir::Local,
482 base: PlaceRef<'tcx, Bx::Value>,
483 var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
484 ) {
485 let Some(dbg_var) = var.dbg_var else { return };
486 let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
487
488 let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
489 calculate_debuginfo_offset(bx, var.projection, base.layout);
490
491 let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
499 && self.mir.local_kind(local) == mir::LocalKind::Arg
500 && (direct_offset != Size::ZERO || !#[allow(non_exhaustive_omitted_patterns)] match &indirect_offsets[..] {
[Size::ZERO] | [] => true,
_ => false,
}matches!(&indirect_offsets[..], [Size::ZERO] | []));
504
505 if should_create_individual_allocas {
506 let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
507 calculate_debuginfo_offset(bx, var.projection, base);
508
509 let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty);
511 let ptr_layout = bx.layout_of(ptr_ty);
512 let alloca = PlaceRef::alloca(bx, ptr_layout);
513 bx.set_var_name(alloca.val.llval, &(var.name.to_string() + ".dbg.spill"));
514
515 bx.store_to_place(place.val.llval, alloca.val);
517
518 bx.dbg_var_addr(
520 dbg_var,
521 dbg_loc,
522 alloca.val.llval,
523 Size::ZERO,
524 &[Size::ZERO],
525 &var.fragment,
526 );
527 } else {
528 bx.dbg_var_addr(
529 dbg_var,
530 dbg_loc,
531 base.val.llval,
532 direct_offset,
533 &indirect_offsets,
534 &var.fragment,
535 );
536 }
537 }
538
539 pub(crate) fn debug_introduce_locals(
540 &self,
541 bx: &mut Bx,
542 consts: Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
543 ) {
544 if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
545 for local in self.locals.indices() {
546 self.debug_introduce_local(bx, local);
547 }
548
549 for ConstDebugInfo { name, source_info, operand, dbg_var, dbg_loc, fragment, .. } in
550 consts.into_iter()
551 {
552 self.set_debug_loc(bx, source_info);
553 let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx);
554 bx.clear_dbg_loc();
555
556 bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], &fragment);
557 }
558 }
559 }
560
561 pub(crate) fn compute_per_local_var_debug_info(
563 &self,
564 bx: &mut Bx,
565 ) -> Option<(
566 PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>,
567 Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
568 )> {
569 let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
570
571 let target_is_msvc = self.cx.sess().target.is_like_msvc;
572
573 if !full_debug_info && self.cx.sess().fewer_names() {
574 return None;
575 }
576
577 let mut per_local = IndexVec::from_elem(::alloc::vec::Vec::new()vec![], &self.mir.local_decls);
578 let mut constants = ::alloc::vec::Vec::new()vec![];
579 let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default();
580 for var in &self.mir.var_debug_info {
581 let dbg_scope_and_span = if full_debug_info {
582 self.adjusted_span_and_dbg_scope(var.source_info)
583 } else {
584 None
585 };
586
587 let var_ty = if let Some(ref fragment) = var.composite {
588 self.monomorphize(fragment.ty)
589 } else {
590 match var.value {
591 mir::VarDebugInfoContents::Place(place) => {
592 self.monomorphized_place_ty(place.as_ref())
593 }
594 mir::VarDebugInfoContents::Const(c) => self.monomorphize(c.ty()),
595 }
596 };
597
598 let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
599 let var_kind = if let Some(arg_index) = var.argument_index
600 && var.composite.is_none()
601 && let mir::VarDebugInfoContents::Place(place) = var.value
602 && place.projection.is_empty()
603 {
604 let arg_index = arg_index as usize;
605 if target_is_msvc {
606 let var_ty_layout = self.cx.layout_of(var_ty);
610 if let BackendRepr::ScalarPair(_, _) = var_ty_layout.backend_repr {
611 VariableKind::LocalVariable
612 } else {
613 VariableKind::ArgumentVariable(arg_index)
614 }
615 } else {
616 VariableKind::ArgumentVariable(arg_index)
619 }
620 } else {
621 VariableKind::LocalVariable
622 };
623
624 if let VariableKind::ArgumentVariable(arg_index) = var_kind {
625 match params_seen.entry((dbg_scope, arg_index)) {
626 Entry::Occupied(o) => o.get().clone(),
627 Entry::Vacant(v) => v
628 .insert(
629 self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span),
630 )
631 .clone(),
632 }
633 } else {
634 self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
635 }
636 });
637
638 let fragment = if let Some(ref fragment) = var.composite {
639 let var_layout = self.cx.layout_of(var_ty);
640
641 let DebugInfoOffset { direct_offset, indirect_offsets, result: fragment_layout } =
642 calculate_debuginfo_offset(bx, &fragment.projection, var_layout);
643 if !indirect_offsets.is_empty() {
::core::panicking::panic("assertion failed: indirect_offsets.is_empty()")
};assert!(indirect_offsets.is_empty());
644
645 if fragment_layout.size == Size::ZERO {
646 continue;
649 } else if fragment_layout.size == var_layout.size {
650 None
653 } else {
654 Some(direct_offset..direct_offset + fragment_layout.size)
655 }
656 } else {
657 None
658 };
659
660 match var.value {
661 mir::VarDebugInfoContents::Place(place) => {
662 per_local[place.local].push(PerLocalVarDebugInfo {
663 name: var.name,
664 source_info: var.source_info,
665 dbg_var,
666 fragment,
667 projection: place.projection,
668 });
669 }
670 mir::VarDebugInfoContents::Const(c) => {
671 if let Some(dbg_var) = dbg_var {
672 let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
673
674 let operand = self.eval_mir_constant_to_operand(bx, &c);
675 constants.push(ConstDebugInfo {
676 name: var.name.to_string(),
677 source_info: var.source_info,
678 operand,
679 dbg_var,
680 dbg_loc,
681 fragment,
682 _phantom: PhantomData,
683 });
684 }
685 }
686 }
687 }
688 Some((per_local, constants))
689 }
690
691 pub(super) fn fill_function_debug_context(&mut self) {
696 if self.cx.sess().opts.debuginfo == DebugInfo::None {
697 return;
698 }
699
700 self.debug_context = Some(FunctionDebugContext {
702 scopes: IndexVec::with_capacity(self.mir.source_scopes.len()),
703 inlined_function_scopes: Default::default(),
704 });
705
706 let variables = if self.cx.sess().opts.debuginfo == DebugInfo::Full {
708 let mut vars = DenseBitSet::new_empty(self.mir.source_scopes.len());
709 for var_debug_info in &self.mir.var_debug_info {
714 vars.insert(var_debug_info.source_info.scope);
715 }
716 Some(vars)
717 } else {
718 None
720 };
721
722 let mut discriminators = FxHashMap::default();
724 for scope in self.mir.source_scopes.indices() {
725 let scope_data = self.make_mir_scope(&variables, &mut discriminators, scope);
726 let _s = self.debug_context.as_mut().unwrap().scopes.push(scope_data);
727 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);
728 }
729 }
730
731 fn make_mir_scope(
732 &mut self,
733 variables: &Option<DenseBitSet<mir::SourceScope>>,
734 discriminators: &mut FxHashMap<BytePos, u32>,
735 scope: mir::SourceScope,
736 ) -> DebugScope<Bx::DIScope, Bx::DILocation> {
737 let scope_data = &self.mir.source_scopes[scope];
738 let parent_scope = if let Some(parent) = scope_data.parent_scope {
739 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());
740 self.debug_context.as_ref().unwrap().scopes[parent]
741 } else {
742 let file = self.cx.sess().source_map().lookup_source_file(self.mir.span.lo());
744 let dbg_scope = self.cx.dbg_scope_fn(self.instance, self.fn_abi, Some(self.llfn));
745 return DebugScope {
746 dbg_scope,
747 inlined_at: None,
748 file_start_pos: file.start_pos,
749 file_end_pos: file.end_position(),
750 };
751 };
752
753 if let Some(vars) = variables
754 && !vars.contains(scope)
755 && scope_data.inlined.is_none()
756 {
757 return parent_scope;
760 }
761
762 let dbg_scope = match scope_data.inlined {
763 Some((callee, _)) => {
764 let callee = self.monomorphize(callee);
765 *self
766 .debug_context
767 .as_mut()
768 .unwrap()
769 .inlined_function_scopes
770 .entry(callee)
771 .or_insert_with(|| {
772 let callee_fn_abi = self.cx.fn_abi_of_instance(callee, ty::List::empty());
773 self.cx.dbg_scope_fn(callee, callee_fn_abi, None)
774 })
775 }
776 None => self.cx.dbg_create_lexical_block(scope_data.span.lo(), parent_scope.dbg_scope),
777 };
778
779 let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
780 let callsite_span = hygiene::walk_chain_collapsed(callsite_span, self.mir.span);
781 let callsite_scope = parent_scope.adjust_dbg_scope_for_span(self.cx, callsite_span);
782 let loc = self.cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
783
784 match discriminators.entry(callsite_span.lo()) {
803 Entry::Occupied(mut o) => {
804 *o.get_mut() += 1;
805 self.cx.dbg_location_clone_with_discriminator(loc, *o.get()).unwrap_or_else(
809 || self.cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP),
810 )
811 }
812 Entry::Vacant(v) => {
813 v.insert(0);
814 loc
815 }
816 }
817 });
818
819 let file = self.cx.sess().source_map().lookup_source_file(scope_data.span.lo());
820 DebugScope {
821 dbg_scope,
822 inlined_at: inlined_at.or(parent_scope.inlined_at),
823 file_start_pos: file.start_pos,
824 file_end_pos: file.end_position(),
825 }
826 }
827}